coverage-report

Code coverage report for All files

npmtest-eslint (v0.0.3)

Code coverage report for All files

Statements: 17.1% (1969 / 11513)      Branches: 2.16% (199 / 9218)      Functions: 2.7% (55 / 2036)      Lines: 17.21% (1969 / 11439)      Ignored: 117 statements, 11 functions, 83 branches     

File Statements Branches Functions Lines
node-npmtest-eslint/ 100% (153 / 153) 100% (126 / 126) 100% (28 / 28) 100% (153 / 153)
node-npmtest-eslint/node_modules/eslint/conf/ 100% (10 / 10) 100% (2 / 2) 100% (0 / 0) 100% (10 / 10)
node-npmtest-eslint/node_modules/eslint/lib/ 18.07% (215 / 1190) 2.69% (21 / 782) 10.88% (16 / 147) 18.13% (215 / 1186)
node-npmtest-eslint/node_modules/eslint/lib/code-path-analysis/ 9.52% (83 / 872) 7.84% (33 / 421) 2.86% (3 / 105) 9.52% (83 / 872)
node-npmtest-eslint/node_modules/eslint/lib/config/ 15.64% (56 / 358) 0.43% (1 / 235) 1.96% (1 / 51) 15.77% (56 / 355)
node-npmtest-eslint/node_modules/eslint/lib/rules/ 16.14% (1313 / 8136) 0.1% (7 / 7193) 0.19% (3 / 1565) 16.25% (1313 / 8078)
node-npmtest-eslint/node_modules/eslint/lib/testers/ 16.25% (26 / 160) 6.82% (6 / 88) 9.52% (2 / 21) 16.25% (26 / 160)
node-npmtest-eslint/node_modules/eslint/lib/token-store/ 20.41% (50 / 245) 0% (0 / 122) 1.89% (1 / 53) 20.41% (50 / 245)
node-npmtest-eslint/node_modules/eslint/lib/util/ 15.98% (62 / 388) 1.2% (3 / 249) 1.52% (1 / 66) 16.36% (62 / 379)
node-npmtest-eslint/node_modules/eslint/lib/util/patterns/ 100% (1 / 1) 100% (0 / 0) 100% (0 / 0) 100% (1 / 1)
Code coverage report for node-npmtest-eslint/

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/

Statements: 100% (153 / 153)      Branches: 100% (126 / 126)      Functions: 100% (28 / 28)      Lines: 100% (153 / 153)      Ignored: 26 statements, 1 function, 30 branches     

All files » node-npmtest-eslint/
File Statements Branches Functions Lines
example.js 100% (83 / 83) 100% (73 / 73) 100% (12 / 12) 100% (83 / 83)
lib.npmtest_eslint.js 100% (16 / 16) 100% (14 / 14) 100% (3 / 3) 100% (16 / 16)
test.js 100% (54 / 54) 100% (39 / 39) 100% (13 / 13) 100% (54 / 54)
Code coverage report for node-npmtest-eslint/example.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/example.js

Statements: 100% (83 / 83)      Branches: 100% (73 / 73)      Functions: 100% (12 / 12)      Lines: 100% (83 / 83)      Ignored: 26 statements, 1 function, 30 branches     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328                                                  2   2         2   2   2 2 2         1             2       2       2   2               1 2           2     2     2 2   1       2     1 1 1   1 1     1 1   1     1   2           1   1   1         1 2 2 3 3 3 3 1     3 3         3       1 3 1       1 1               1   1 1 1   1   1                                                                                                                                                                                       1 1                       1     6 6   1   2   1   2         1 1   1         1             1     1 1     1 1   1 1 1 1 1 1 1   1 1   1        
/*
example.js
 
quickstart example
 
instruction
    1. save this script as example.js
    2. run the shell command:
        $ npm install npmtest-eslint && PORT=8081 node example.js
    3. play with the browser-demo on http://127.0.0.1:8081
*/
 
 
 
/* istanbul instrument in package npmtest_eslint */
/*jslint
    bitwise: true,
    browser: true,
    maxerr: 8,
    maxlen: 96,
    node: true,
    nomen: true,
    regexp: true,
    stupid: true
*/
(function () {
    'use strict';
    var local;
 
 
 
    // run shared js-env code - pre-init
    (function () {
        // init local
        local = {};
        // init modeJs
        local.modeJs = (function () {
            try {
                return typeof navigator.userAgent === 'string' &&
                    typeof document.querySelector('body') === 'object' &&
                    typeof XMLHttpRequest.prototype.open === 'function' &&
                    'browser';
            } catch (errorCaughtBrowser) {
                return module.exports &&
                    typeof process.versions.node === 'string' &&
                    typeof require('http').createServer === 'function' &&
                    'node';
            }
        }());
        // init global
        local.global = local.modeJs === 'browser'
            ? window
            : global;
        // init utility2_rollup
        local = local.global.utility2_rollup || (local.modeJs === 'browser'
            ? local.global.utility2_npmtest_eslint
            : global.utility2_moduleExports);
        // export local
        local.global.local = local;
    }());
    switch (local.modeJs) {
 
 
 
    // post-init
    // run browser js-env code - post-init
    /* istanbul ignore next */
    case 'browser':
        local.testRunBrowser = function (event) {
            Eif (!event || (event &&
                    event.currentTarget &&
                    event.currentTarget.className &&
                    event.currentTarget.className.includes &&
                    event.currentTarget.className.includes('onreset'))) {
                // reset output
                Array.from(
                    document.querySelectorAll('body > .resettable')
                ).forEach(function (element) {
                    switch (element.tagName) {
                    case 'INPUT':
                    case 'TEXTAREA':
                        element.value = '';
                        break;
                    default:
                        element.textContent = '';
                    }
                });
            }
            switch (event && event.currentTarget && event.currentTarget.id) {
            case 'testRunButton1':
                // show tests
                Eif (document.querySelector('#testReportDiv1').style.display === 'none') {
                    document.querySelector('#testReportDiv1').style.display = 'block';
                    document.querySelector('#testRunButton1').textContent =
                        'hide internal test';
                    local.modeTest = true;
                    local.testRunDefault(local);
                // hide tests
                } else {
                    document.querySelector('#testReportDiv1').style.display = 'none';
                    document.querySelector('#testRunButton1').textContent = 'run internal test';
                }
                break;
            // custom-case
            default:
                break;
            }
            Iif (document.querySelector('#inputTextareaEval1') && (!event || (event &&
                    event.currentTarget &&
                    event.currentTarget.className &&
                    event.currentTarget.className.includes &&
                    event.currentTarget.className.includes('oneval')))) {
                // try to eval input-code
                try {
                    /*jslint evil: true*/
                    eval(document.querySelector('#inputTextareaEval1').value);
                } catch (errorCaught) {
                    console.error(errorCaught);
                }
            }
        };
        // log stderr and stdout to #outputTextareaStdout1
        ['error', 'log'].forEach(function (key) {
            console[key + '_original'] = console[key];
            console[key] = function () {
                var element;
                console[key + '_original'].apply(console, arguments);
                element = document.querySelector('#outputTextareaStdout1');
                Iif (!element) {
                    return;
                }
                // append text to #outputTextareaStdout1
                element.value += Array.from(arguments).map(function (arg) {
                    return typeof arg === 'string'
                        ? arg
                        : JSON.stringify(arg, null, 4);
                }).join(' ') + '\n';
                // scroll textarea to bottom
                element.scrollTop = element.scrollHeight;
            };
        });
        // init event-handling
        ['change', 'click', 'keyup'].forEach(function (event) {
            Array.from(document.querySelectorAll('.on' + event)).forEach(function (element) {
                element.addEventListener(event, local.testRunBrowser);
            });
        });
        // run tests
        local.testRunBrowser();
        break;
 
 
 
    // run node js-env code - post-init
    /* istanbul ignore next */
    case 'node':
        // export local
        module.exports = local;
        // require modules
        local.fs = require('fs');
        local.http = require('http');
        local.url = require('url');
        // init assets
        local.assetsDict = local.assetsDict || {};
        /* jslint-ignore-begin */
        local.assetsDict['/assets.index.template.html'] = '\
<!doctype html>\n\
<html lang="en">\n\
<head>\n\
<meta charset="UTF-8">\n\
<meta name="viewport" content="width=device-width, initial-scale=1">\n\
<title>{{env.npm_package_name}} (v{{env.npm_package_version}})</title>\n\
<style>\n\
/*csslint\n\
    box-sizing: false,\n\
    universal-selector: false\n\
*/\n\
* {\n\
    box-sizing: border-box;\n\
}\n\
body {\n\
    background: #dde;\n\
    font-family: Arial, Helvetica, sans-serif;\n\
    margin: 2rem;\n\
}\n\
body > * {\n\
    margin-bottom: 1rem;\n\
}\n\
.utility2FooterDiv {\n\
    margin-top: 20px;\n\
    text-align: center;\n\
}\n\
</style>\n\
<style>\n\
/*csslint\n\
*/\n\
textarea {\n\
    font-family: monospace;\n\
    height: 10rem;\n\
    width: 100%;\n\
}\n\
textarea[readonly] {\n\
    background: #ddd;\n\
}\n\
</style>\n\
</head>\n\
<body>\n\
<!-- utility2-comment\n\
<div id="ajaxProgressDiv1" style="background: #d00; height: 2px; left: 0; margin: 0; padding: 0; position: fixed; top: 0; transition: background 0.5s, width 1.5s; width: 25%;"></div>\n\
utility2-comment -->\n\
<h1>\n\
<!-- utility2-comment\n\
    <a\n\
        {{#if env.npm_package_homepage}}\n\
        href="{{env.npm_package_homepage}}"\n\
        {{/if env.npm_package_homepage}}\n\
        target="_blank"\n\
    >\n\
utility2-comment -->\n\
        {{env.npm_package_name}} (v{{env.npm_package_version}})\n\
<!-- utility2-comment\n\
    </a>\n\
utility2-comment -->\n\
</h1>\n\
<h3>{{env.npm_package_description}}</h3>\n\
<!-- utility2-comment\n\
<h4><a download href="assets.app.js">download standalone app</a></h4>\n\
<button class="onclick onreset" id="testRunButton1">run internal test</button><br>\n\
<div id="testReportDiv1" style="display: none;"></div>\n\
utility2-comment -->\n\
\n\
\n\
\n\
<label>stderr and stdout</label>\n\
<textarea class="resettable" id="outputTextareaStdout1" readonly></textarea>\n\
<!-- utility2-comment\n\
{{#if isRollup}}\n\
<script src="assets.app.js"></script>\n\
{{#unless isRollup}}\n\
utility2-comment -->\n\
<script src="assets.utility2.rollup.js"></script>\n\
<script src="jsonp.utility2._stateInit?callback=window.utility2._stateInit"></script>\n\
<script src="assets.npmtest_eslint.rollup.js"></script>\n\
<script src="assets.example.js"></script>\n\
<script src="assets.test.js"></script>\n\
<!-- utility2-comment\n\
{{/if isRollup}}\n\
utility2-comment -->\n\
<div class="utility2FooterDiv">\n\
    [ this app was created with\n\
    <a href="https://github.com/kaizhu256/node-utility2" target="_blank">utility2</a>\n\
    ]\n\
</div>\n\
</body>\n\
</html>\n\
';
        /* jslint-ignore-end */
        Iif (local.templateRender) {
            local.assetsDict['/'] = local.templateRender(
                local.assetsDict['/assets.index.template.html'],
                {
                    env: local.objectSetDefault(local.env, {
                        npm_package_description: 'the greatest app in the world!',
                        npm_package_name: 'my-app',
                        npm_package_nameAlias: 'my_app',
                        npm_package_version: '0.0.1'
                    })
                }
            );
        } else {
            local.assetsDict['/'] = local.assetsDict['/assets.index.template.html']
                .replace((/\{\{env\.(\w+?)\}\}/g), function (match0, match1) {
                    // jslint-hack
                    String(match0);
                    switch (match1) {
                    case 'npm_package_description':
                        return 'the greatest app in the world!';
                    case 'npm_package_name':
                        return 'my-app';
                    case 'npm_package_nameAlias':
                        return 'my_app';
                    case 'npm_package_version':
                        return '0.0.1';
                    }
                });
        }
        // run the cli
        Eif (local.global.utility2_rollup || module !== require.main) {
            break;
        }
        local.assetsDict['/assets.example.js'] =
            local.assetsDict['/assets.example.js'] ||
            local.fs.readFileSync(__filename, 'utf8');
        // bug-workaround - long $npm_package_buildCustomOrg
        /* jslint-ignore-begin */
        local.assetsDict['/assets.npmtest_eslint.rollup.js'] =
            local.assetsDict['/assets.npmtest_eslint.rollup.js'] ||
            local.fs.readFileSync(
                local.npmtest_eslint.__dirname + '/lib.npmtest_eslint.js',
                'utf8'
            ).replace((/^#!/), '//');
        /* jslint-ignore-end */
        local.assetsDict['/favicon.ico'] = local.assetsDict['/favicon.ico'] || '';
        // if $npm_config_timeout_exit exists,
        // then exit this process after $npm_config_timeout_exit ms
        if (Number(process.env.npm_config_timeout_exit)) {
            setTimeout(process.exit, Number(process.env.npm_config_timeout_exit));
        }
        // start server
        if (local.global.utility2_serverHttp1) {
            break;
        }
        process.env.PORT = process.env.PORT || '8081';
        console.error('server starting on port ' + process.env.PORT);
        local.http.createServer(function (request, response) {
            request.urlParsed = local.url.parse(request.url);
            if (local.assetsDict[request.urlParsed.pathname] !== undefined) {
                response.end(local.assetsDict[request.urlParsed.pathname]);
                return;
            }
            response.statusCode = 404;
            response.end();
        }).listen(process.env.PORT);
        break;
    }
}());
 
 
Code coverage report for node-npmtest-eslint/lib.npmtest_eslint.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/lib.npmtest_eslint.js

Statements: 100% (16 / 16)      Branches: 100% (14 / 14)      Functions: 100% (3 / 3)      Lines: 100% (16 / 16)      Ignored: none     

All files » node-npmtest-eslint/ » lib.npmtest_eslint.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55                      2   2         2   2   2 2 2         1             2       2   2   2 1   1 1 1          
/* istanbul instrument in package npmtest_eslint */
/*jslint
    bitwise: true,
    browser: true,
    maxerr: 8,
    maxlen: 96,
    node: true,
    nomen: true,
    regexp: true,
    stupid: true
*/
(function () {
    'use strict';
    var local;
 
 
 
    // run shared js-env code - pre-init
    (function () {
        // init local
        local = {};
        // init modeJs
        local.modeJs = (function () {
            try {
                return typeof navigator.userAgent === 'string' &&
                    typeof document.querySelector('body') === 'object' &&
                    typeof XMLHttpRequest.prototype.open === 'function' &&
                    'browser';
            } catch (errorCaughtBrowser) {
                return module.exports &&
                    typeof process.versions.node === 'string' &&
                    typeof require('http').createServer === 'function' &&
                    'node';
            }
        }());
        // init global
        local.global = local.modeJs === 'browser'
            ? window
            : global;
        // init utility2_rollup
        local = local.global.utility2_rollup || local;
        // init lib
        local.local = local.npmtest_eslint = local;
        // init exports
        if (local.modeJs === 'browser') {
            local.global.utility2_npmtest_eslint = local;
        } else {
            module.exports = local;
            module.exports.__dirname = __dirname;
            module.exports.module = module;
        }
    }());
}());
 
 
Code coverage report for node-npmtest-eslint/test.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/test.js

Statements: 100% (54 / 54)      Branches: 100% (39 / 39)      Functions: 100% (13 / 13)      Lines: 100% (54 / 54)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197                      2   2         2   2   2 2 2         1             2     2     1       1     1   1     2           2 2   2           1           1           2 2   2           1             1       1     1             1             1 1     1             1 1 1 1 1 1     1         2 2     1             2 2     1             2 2     1             2 2     1             1 1       1 1        
/* istanbul instrument in package npmtest_eslint */
/*jslint
    bitwise: true,
    browser: true,
    maxerr: 8,
    maxlen: 96,
    node: true,
    nomen: true,
    regexp: true,
    stupid: true
*/
(function () {
    'use strict';
    var local;
 
 
 
    // run shared js-env code - pre-init
    (function () {
        // init local
        local = {};
        // init modeJs
        local.modeJs = (function () {
            try {
                return typeof navigator.userAgent === 'string' &&
                    typeof document.querySelector('body') === 'object' &&
                    typeof XMLHttpRequest.prototype.open === 'function' &&
                    'browser';
            } catch (errorCaughtBrowser) {
                return module.exports &&
                    typeof process.versions.node === 'string' &&
                    typeof require('http').createServer === 'function' &&
                    'node';
            }
        }());
        // init global
        local.global = local.modeJs === 'browser'
            ? window
            : global;
        switch (local.modeJs) {
        // re-init local from window.local
        case 'browser':
            local = local.global.utility2.objectSetDefault(
                local.global.utility2_rollup || local.global.local,
                local.global.utility2
            );
            break;
        // re-init local from example.js
        case 'node':
            local = (local.global.utility2_rollup || require('utility2'))
                .requireExampleJsFromReadme();
            break;
        }
        // export local
        local.global.local = local;
    }());
 
 
 
    // run shared js-env code - function
    (function () {
        return;
    }());
    switch (local.modeJs) {
 
 
 
    // run browser js-env code - function
    case 'browser':
        break;
 
 
 
    // run node js-env code - function
    case 'node':
        break;
    }
 
 
 
    // run shared js-env code - post-init
    (function () {
        return;
    }());
    switch (local.modeJs) {
 
 
 
    // run browser js-env code - post-init
    case 'browser':
        local.testCase_browser_nullCase = local.testCase_browser_nullCase || function (
            options,
            onError
        ) {
        /*
         * this function will test browsers's null-case handling-behavior-behavior
         */
            onError(null, options);
        };
 
        // run tests
        local.nop(local.modeTest &&
            document.querySelector('#testRunButton1') &&
            document.querySelector('#testRunButton1').click());
        break;
 
 
 
    // run node js-env code - post-init
    /* istanbul ignore next */
    case 'node':
        local.testCase_buildApidoc_default = local.testCase_buildApidoc_default || function (
            options,
            onError
        ) {
        /*
         * this function will test buildApidoc's default handling-behavior-behavior
         */
            options = { modulePathList: module.paths };
            local.buildApidoc(options, onError);
        };
 
        local.testCase_buildApp_default = local.testCase_buildApp_default || function (
            options,
            onError
        ) {
        /*
         * this function will test buildApp's default handling-behavior-behavior
         */
            local.testCase_buildReadme_default(options, local.onErrorThrow);
            local.testCase_buildLib_default(options, local.onErrorThrow);
            local.testCase_buildTest_default(options, local.onErrorThrow);
            local.testCase_buildCustomOrg_default(options, local.onErrorThrow);
            options = [];
            local.buildApp(options, onError);
        };
 
        local.testCase_buildCustomOrg_default = local.testCase_buildCustomOrg_default ||
            function (options, onError) {
            /*
             * this function will test buildCustomOrg's default handling-behavior
             */
                options = {};
                local.buildCustomOrg(options, onError);
            };
 
        local.testCase_buildLib_default = local.testCase_buildLib_default || function (
            options,
            onError
        ) {
        /*
         * this function will test buildLib's default handling-behavior
         */
            options = {};
            local.buildLib(options, onError);
        };
 
        local.testCase_buildReadme_default = local.testCase_buildReadme_default || function (
            options,
            onError
        ) {
        /*
         * this function will test buildReadme's default handling-behavior-behavior
         */
            options = {};
            local.buildReadme(options, onError);
        };
 
        local.testCase_buildTest_default = local.testCase_buildTest_default || function (
            options,
            onError
        ) {
        /*
         * this function will test buildTest's default handling-behavior
         */
            options = {};
            local.buildTest(options, onError);
        };
 
        local.testCase_webpage_default = local.testCase_webpage_default || function (
            options,
            onError
        ) {
        /*
         * this function will test webpage's default handling-behavior
         */
            options = { modeCoverageMerge: true, url: local.serverLocalHost + '?modeTest=1' };
            local.browserTest(options, onError);
        };
 
        // run test-server
        local.testRunServer(local);
        break;
    }
}());
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/conf/

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/conf/

Statements: 100% (10 / 10)      Branches: 100% (2 / 2)      Functions: 100% (0 / 0)      Lines: 100% (10 / 10)      Ignored: none     

All files » node-npmtest-eslint/node_modules/eslint/conf/
File Statements Branches Functions Lines
cli-options.js 100% (1 / 1) 100% (0 / 0) 100% (0 / 0) 100% (1 / 1)
environments.js 100% (2 / 2) 100% (0 / 0) 100% (0 / 0) 100% (2 / 2)
eslint-all.js 100% (6 / 6) 100% (2 / 2) 100% (0 / 0) 100% (6 / 6)
eslint-recommended.js 100% (1 / 1) 100% (0 / 0) 100% (0 / 0) 100% (1 / 1)
Code coverage report for node-npmtest-eslint/node_modules/eslint/conf/cli-options.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/conf/cli-options.js

Statements: 100% (1 / 1)      Branches: 100% (0 / 0)      Functions: 100% (0 / 0)      Lines: 100% (1 / 1)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31              1                                              
/**
 * @fileoverview Default CLIEngineOptions.
 * @author Ian VanSchooten
 */
 
"use strict";
 
module.exports = {
    configFile: null,
    baseConfig: false,
    rulePaths: [],
    useEslintrc: true,
    envs: [],
    globals: [],
    rules: {},
    extensions: [".js"],
    ignore: true,
    ignorePath: null,
    parser: "",     // must be empty
    cache: false,
 
    // in order to honor the cacheFile option if specified
    // this option should not have a default value otherwise
    // it will always be used
    cacheLocation: "",
    cacheFile: ".eslintcache",
    fix: false,
    allowInlineConfig: true
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/conf/environments.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/conf/environments.js

Statements: 100% (2 / 2)      Branches: 100% (0 / 0)      Functions: 100% (0 / 0)      Lines: 100% (2 / 2)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109                    1           1                                                                                                                                                                                        
/**
 * @fileoverview Defines environment settings and globals.
 * @author Elan Shanker
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const globals = require("globals");
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
module.exports = {
    builtin: globals.es5,
    browser: {
        globals: globals.browser
    },
    node: {
        globals: globals.node,
        parserOptions: {
            ecmaFeatures: {
                globalReturn: true
            }
        }
    },
    commonjs: {
        globals: globals.commonjs,
        parserOptions: {
            ecmaFeatures: {
                globalReturn: true
            }
        }
    },
    "shared-node-browser": {
        globals: globals["shared-node-browser"]
    },
    worker: {
        globals: globals.worker
    },
    amd: {
        globals: globals.amd
    },
    mocha: {
        globals: globals.mocha
    },
    jasmine: {
        globals: globals.jasmine
    },
    jest: {
        globals: globals.jest
    },
    phantomjs: {
        globals: globals.phantomjs
    },
    jquery: {
        globals: globals.jquery
    },
    qunit: {
        globals: globals.qunit
    },
    prototypejs: {
        globals: globals.prototypejs
    },
    shelljs: {
        globals: globals.shelljs
    },
    meteor: {
        globals: globals.meteor
    },
    mongo: {
        globals: globals.mongo
    },
    protractor: {
        globals: globals.protractor
    },
    applescript: {
        globals: globals.applescript
    },
    nashorn: {
        globals: globals.nashorn
    },
    serviceworker: {
        globals: globals.serviceworker
    },
    atomtest: {
        globals: globals.atomtest
    },
    embertest: {
        globals: globals.embertest
    },
    webextensions: {
        globals: globals.webextensions
    },
    es6: {
        globals: globals.es6,
        parserOptions: {
            ecmaVersion: 6
        }
    },
    greasemonkey: {
        globals: globals.greasemonkey
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/conf/eslint-all.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/conf/eslint-all.js

Statements: 100% (6 / 6)      Branches: 100% (2 / 2)      Functions: 100% (0 / 0)      Lines: 100% (6 / 6)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32                      1             1 244 240   244             1    
/**
 * @fileoverview Config to enable all rules.
 * @author Robert Fletcher
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const load = require("../lib/load-rules"),
    rules = require("../lib/rules");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const enabledRules = Object.keys(load()).reduce((result, ruleId) => {
    if (!rules.get(ruleId).meta.deprecated) {
        result[ruleId] = "error";
    }
    return result;
}, {});
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
module.exports = { rules: enabledRules };
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/conf/eslint-recommended.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/conf/eslint-recommended.js

Statements: 100% (1 / 1)      Branches: 100% (0 / 0)      Functions: 100% (0 / 0)      Lines: 100% (1 / 1)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266                      1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
/**
 * @fileoverview Configuration applied when a user configuration extends from
 * eslint:recommended.
 * @author Nicholas C. Zakas
 */
 
"use strict";
 
/* eslint sort-keys: ["error", "asc"], quote-props: ["error", "consistent"] */
/* eslint-disable sort-keys */
 
module.exports = {
    parser: "espree",
    ecmaFeatures: {},
 
    rules: {
 
        /* eslint-enable sort-keys */
        "accessor-pairs": "off",
        "array-bracket-spacing": "off",
        "array-callback-return": "off",
        "arrow-body-style": "off",
        "arrow-parens": "off",
        "arrow-spacing": "off",
        "block-scoped-var": "off",
        "block-spacing": "off",
        "brace-style": "off",
        "callback-return": "off",
        "camelcase": "off",
        "capitalized-comments": "off",
        "class-methods-use-this": "off",
        "comma-dangle": "off",
        "comma-spacing": "off",
        "comma-style": "off",
        "complexity": "off",
        "computed-property-spacing": "off",
        "consistent-return": "off",
        "consistent-this": "off",
        "constructor-super": "error",
        "curly": "off",
        "default-case": "off",
        "dot-location": "off",
        "dot-notation": "off",
        "eol-last": "off",
        "eqeqeq": "off",
        "func-call-spacing": "off",
        "func-name-matching": "off",
        "func-names": "off",
        "func-style": "off",
        "generator-star-spacing": "off",
        "global-require": "off",
        "guard-for-in": "off",
        "handle-callback-err": "off",
        "id-blacklist": "off",
        "id-length": "off",
        "id-match": "off",
        "indent": "off",
        "init-declarations": "off",
        "jsx-quotes": "off",
        "key-spacing": "off",
        "keyword-spacing": "off",
        "line-comment-position": "off",
        "linebreak-style": "off",
        "lines-around-comment": "off",
        "lines-around-directive": "off",
        "max-depth": "off",
        "max-len": "off",
        "max-lines": "off",
        "max-nested-callbacks": "off",
        "max-params": "off",
        "max-statements": "off",
        "max-statements-per-line": "off",
        "multiline-ternary": "off",
        "new-cap": "off",
        "new-parens": "off",
        "newline-after-var": "off",
        "newline-before-return": "off",
        "newline-per-chained-call": "off",
        "no-alert": "off",
        "no-array-constructor": "off",
        "no-await-in-loop": "off",
        "no-bitwise": "off",
        "no-caller": "off",
        "no-case-declarations": "error",
        "no-catch-shadow": "off",
        "no-class-assign": "error",
        "no-compare-neg-zero": "off",
        "no-cond-assign": "error",
        "no-confusing-arrow": "off",
        "no-console": "error",
        "no-const-assign": "error",
        "no-constant-condition": "error",
        "no-continue": "off",
        "no-control-regex": "error",
        "no-debugger": "error",
        "no-delete-var": "error",
        "no-div-regex": "off",
        "no-dupe-args": "error",
        "no-dupe-class-members": "error",
        "no-dupe-keys": "error",
        "no-duplicate-case": "error",
        "no-duplicate-imports": "off",
        "no-else-return": "off",
        "no-empty": "error",
        "no-empty-character-class": "error",
        "no-empty-function": "off",
        "no-empty-pattern": "error",
        "no-eq-null": "off",
        "no-eval": "off",
        "no-ex-assign": "error",
        "no-extend-native": "off",
        "no-extra-bind": "off",
        "no-extra-boolean-cast": "error",
        "no-extra-label": "off",
        "no-extra-parens": "off",
        "no-extra-semi": "error",
        "no-fallthrough": "error",
        "no-floating-decimal": "off",
        "no-func-assign": "error",
        "no-global-assign": "error",
        "no-implicit-coercion": "off",
        "no-implicit-globals": "off",
        "no-implied-eval": "off",
        "no-inline-comments": "off",
        "no-inner-declarations": "error",
        "no-invalid-regexp": "error",
        "no-invalid-this": "off",
        "no-irregular-whitespace": "error",
        "no-iterator": "off",
        "no-label-var": "off",
        "no-labels": "off",
        "no-lone-blocks": "off",
        "no-lonely-if": "off",
        "no-loop-func": "off",
        "no-magic-numbers": "off",
        "no-mixed-operators": "off",
        "no-mixed-requires": "off",
        "no-mixed-spaces-and-tabs": "error",
        "no-multi-assign": "off",
        "no-multi-spaces": "off",
        "no-multi-str": "off",
        "no-multiple-empty-lines": "off",
        "no-native-reassign": "off",
        "no-negated-condition": "off",
        "no-negated-in-lhs": "off",
        "no-nested-ternary": "off",
        "no-new": "off",
        "no-new-func": "off",
        "no-new-object": "off",
        "no-new-require": "off",
        "no-new-symbol": "error",
        "no-new-wrappers": "off",
        "no-obj-calls": "error",
        "no-octal": "error",
        "no-octal-escape": "off",
        "no-param-reassign": "off",
        "no-path-concat": "off",
        "no-plusplus": "off",
        "no-process-env": "off",
        "no-process-exit": "off",
        "no-proto": "off",
        "no-prototype-builtins": "off",
        "no-redeclare": "error",
        "no-regex-spaces": "error",
        "no-restricted-globals": "off",
        "no-restricted-imports": "off",
        "no-restricted-modules": "off",
        "no-restricted-properties": "off",
        "no-restricted-syntax": "off",
        "no-return-assign": "off",
        "no-return-await": "off",
        "no-script-url": "off",
        "no-self-assign": "error",
        "no-self-compare": "off",
        "no-sequences": "off",
        "no-shadow": "off",
        "no-shadow-restricted-names": "off",
        "no-spaced-func": "off",
        "no-sparse-arrays": "error",
        "no-sync": "off",
        "no-tabs": "off",
        "no-template-curly-in-string": "off",
        "no-ternary": "off",
        "no-this-before-super": "error",
        "no-throw-literal": "off",
        "no-trailing-spaces": "off",
        "no-undef": "error",
        "no-undef-init": "off",
        "no-undefined": "off",
        "no-underscore-dangle": "off",
        "no-unexpected-multiline": "error",
        "no-unmodified-loop-condition": "off",
        "no-unneeded-ternary": "off",
        "no-unreachable": "error",
        "no-unsafe-finally": "error",
        "no-unsafe-negation": "error",
        "no-unused-expressions": "off",
        "no-unused-labels": "error",
        "no-unused-vars": "error",
        "no-use-before-define": "off",
        "no-useless-call": "off",
        "no-useless-computed-key": "off",
        "no-useless-concat": "off",
        "no-useless-constructor": "off",
        "no-useless-escape": "off",
        "no-useless-rename": "off",
        "no-useless-return": "off",
        "no-var": "off",
        "no-void": "off",
        "no-warning-comments": "off",
        "no-whitespace-before-property": "off",
        "no-with": "off",
        "nonblock-statement-body-position": "off",
        "object-curly-newline": "off",
        "object-curly-spacing": ["off", "never"],
        "object-property-newline": "off",
        "object-shorthand": "off",
        "one-var": "off",
        "one-var-declaration-per-line": "off",
        "operator-assignment": "off",
        "operator-linebreak": "off",
        "padded-blocks": "off",
        "prefer-arrow-callback": "off",
        "prefer-const": "off",
        "prefer-destructuring": "off",
        "prefer-numeric-literals": "off",
        "prefer-promise-reject-errors": "off",
        "prefer-reflect": "off",
        "prefer-rest-params": "off",
        "prefer-spread": "off",
        "prefer-template": "off",
        "quote-props": "off",
        "quotes": "off",
        "radix": "off",
        "require-await": "off",
        "require-jsdoc": "off",
        "require-yield": "error",
        "rest-spread-spacing": "off",
        "semi": "off",
        "semi-spacing": "off",
        "sort-imports": "off",
        "sort-keys": "off",
        "sort-vars": "off",
        "space-before-blocks": "off",
        "space-before-function-paren": "off",
        "space-in-parens": "off",
        "space-infix-ops": "off",
        "space-unary-ops": "off",
        "spaced-comment": "off",
        "strict": "off",
        "symbol-description": "off",
        "template-curly-spacing": "off",
        "template-tag-spacing": "off",
        "unicode-bom": "off",
        "use-isnan": "error",
        "valid-jsdoc": "off",
        "valid-typeof": "error",
        "vars-on-top": "off",
        "wrap-iife": "off",
        "wrap-regex": "off",
        "yield-star-spacing": "off",
        "yoda": "off"
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/

Statements: 18.07% (215 / 1190)      Branches: 2.69% (21 / 782)      Functions: 10.88% (16 / 147)      Lines: 18.13% (215 / 1186)      Ignored: 39 statements, 7 functions, 15 branches     

All files » node-npmtest-eslint/node_modules/eslint/lib/
File Statements Branches Functions Lines
api.js 100% (1 / 1) 100% (0 / 0) 100% (0 / 0) 100% (1 / 1)
ast-utils.js 18.37% (45 / 245) 0% (0 / 279) 4.08% (2 / 49) 18.52% (45 / 243)
cli-engine.js 9.95% (20 / 201) 0% (0 / 102) 0% (0 / 21) 10% (20 / 200)
config.js 7.89% (9 / 114) 1.19% (1 / 84) 0% (0 / 8) 7.89% (9 / 114)
eslint.js 10.86% (43 / 396) 0% (0 / 233) 2.78% (1 / 36) 10.89% (43 / 395)
file-finder.js 9.09% (4 / 44) 0% (0 / 18) 0% (0 / 4) 9.09% (4 / 44)
ignored-paths.js 13.89% (10 / 72) 0% (0 / 36) 0% (0 / 8) 13.89% (10 / 72)
load-rules.js 90.91% (10 / 11) 75% (3 / 4) 100% (1 / 1) 90.91% (10 / 11)
logging.js 100% (3 / 3) 100% (0 / 0) 100% (2 / 2) 100% (3 / 3)
options.js 100% (2 / 2) 100% (0 / 0) 100% (0 / 0) 100% (2 / 2)
rule-context.js 20% (5 / 25) 0% (0 / 6) 20% (1 / 5) 20% (5 / 25)
rules.js 55.17% (16 / 29) 25% (1 / 4) 42.86% (3 / 7) 55.17% (16 / 29)
timing.js 100% (47 / 47) 100% (16 / 16) 100% (6 / 6) 100% (47 / 47)
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/api.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/api.js

Statements: 100% (1 / 1)      Branches: 100% (0 / 0)      Functions: 100% (0 / 0)      Lines: 100% (1 / 1)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15              1              
/**
 * @fileoverview Expose out ESLint and CLI to require.
 * @author Ian Christian Myers
 */
 
"use strict";
 
module.exports = {
    linter: require("./eslint"),
    CLIEngine: require("./cli-engine"),
    RuleTester: require("./testers/rule-tester"),
    SourceCode: require("./util/source-code")
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/ast-utils.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/ast-utils.js

Statements: 18.37% (45 / 245)      Branches: 0% (0 / 279)      Functions: 4.08% (2 / 49)      Lines: 18.52% (45 / 243)      Ignored: 1 statement     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258                      1           1 1 1 1 1 1 1     1 1 1     1                   1                                               1                 1                 1                                         1                                 1                   1                                   1                         1                 1                               1                               1                                         1 9                 1                                         1                             1                   1                   1                   1                   1                   1                   1                   1                   1                   1                   1                   1                     1                     1 1             1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
/**
 * @fileoverview Common utils for AST.
 * @author Gyandeep Singh
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const esutils = require("esutils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const anyFunctionPattern = /^(?:Function(?:Declaration|Expression)|ArrowFunctionExpression)$/;
const anyLoopPattern = /^(?:DoWhile|For|ForIn|ForOf|While)Statement$/;
const arrayOrTypedArrayPattern = /Array$/;
const arrayMethodPattern = /^(?:every|filter|find|findIndex|forEach|map|some)$/;
const bindOrCallOrApplyPattern = /^(?:bind|call|apply)$/;
const breakableTypePattern = /^(?:(?:Do)?While|For(?:In|Of)?|Switch)Statement$/;
const thisTagPattern = /^[\s*]*@this/m;
 
 
const COMMENTS_IGNORE_PATTERN = /^\s*(?:eslint|jshint\s+|jslint\s+|istanbul\s+|globals?\s+|exported\s+|jscs)/;
const LINEBREAKS = new Set(["\r\n", "\r", "\n", "\u2028", "\u2029"]);
const LINEBREAK_MATCHER = /\r\n|[\r\n\u2028\u2029]/;
 
// A set of node types that can contain a list of statements
const STATEMENT_LIST_PARENTS = new Set(["Program", "BlockStatement", "SwitchCase"]);
 
/**
 * Checks reference if is non initializer and writable.
 * @param {Reference} reference - A reference to check.
 * @param {int} index - The index of the reference in the references.
 * @param {Reference[]} references - The array that the reference belongs to.
 * @returns {boolean} Success/Failure
 * @private
 */
function isModifyingReference(reference, index, references) {
    const identifier = reference.identifier;
 
    /*
     * Destructuring assignments can have multiple default value, so
     * possibly there are multiple writeable references for the same
     * identifier.
     */
    const modifyingDifferentIdentifier = index === 0 ||
        references[index - 1].identifier !== identifier;
 
    return (identifier &&
        reference.init === false &&
        reference.isWrite() &&
        modifyingDifferentIdentifier
    );
}
 
/**
 * Checks whether the given string starts with uppercase or not.
 *
 * @param {string} s - The string to check.
 * @returns {boolean} `true` if the string starts with uppercase.
 */
function startsWithUpperCase(s) {
    return s[0] !== s[0].toLocaleLowerCase();
}
 
/**
 * Checks whether or not a node is a constructor.
 * @param {ASTNode} node - A function node to check.
 * @returns {boolean} Wehether or not a node is a constructor.
 */
function isES5Constructor(node) {
    return (node.id && startsWithUpperCase(node.id.name));
}
 
/**
 * Finds a function node from ancestors of a node.
 * @param {ASTNode} node - A start node to find.
 * @returns {Node|null} A found function node.
 */
function getUpperFunction(node) {
    while (node) {
        if (anyFunctionPattern.test(node.type)) {
            return node;
        }
        node = node.parent;
    }
    return null;
}
 
/**
 * Checks whether a given node is a function node or not.
 * The following types are function nodes:
 *
 * - ArrowFunctionExpression
 * - FunctionDeclaration
 * - FunctionExpression
 *
 * @param {ASTNode|null} node - A node to check.
 * @returns {boolean} `true` if the node is a function node.
 */
function isFunction(node) {
    return Boolean(node && anyFunctionPattern.test(node.type));
}
 
/**
 * Checks whether a given node is a loop node or not.
 * The following types are loop nodes:
 *
 * - DoWhileStatement
 * - ForInStatement
 * - ForOfStatement
 * - ForStatement
 * - WhileStatement
 *
 * @param {ASTNode|null} node - A node to check.
 * @returns {boolean} `true` if the node is a loop node.
 */
function isLoop(node) {
    return Boolean(node && anyLoopPattern.test(node.type));
}
 
/**
 * Checks whether the given node is in a loop or not.
 *
 * @param {ASTNode} node - The node to check.
 * @returns {boolean} `true` if the node is in a loop.
 */
function isInLoop(node) {
    while (node && !isFunction(node)) {
        if (isLoop(node)) {
            return true;
        }
 
        node = node.parent;
    }
 
    return false;
}
 
/**
 * Checks whether or not a node is `null` or `undefined`.
 * @param {ASTNode} node - A node to check.
 * @returns {boolean} Whether or not the node is a `null` or `undefined`.
 * @public
 */
function isNullOrUndefined(node) {
    return (
        module.exports.isNullLiteral(node) ||
        (node.type === "Identifier" && node.name === "undefined") ||
        (node.type === "UnaryExpression" && node.operator === "void")
    );
}
 
/**
 * Checks whether or not a node is callee.
 * @param {ASTNode} node - A node to check.
 * @returns {boolean} Whether or not the node is callee.
 */
function isCallee(node) {
    return node.parent.type === "CallExpression" && node.parent.callee === node;
}
 
/**
 * Checks whether or not a node is `Reflect.apply`.
 * @param {ASTNode} node - A node to check.
 * @returns {boolean} Whether or not the node is a `Reflect.apply`.
 */
function isReflectApply(node) {
    return (
        node.type === "MemberExpression" &&
        node.object.type === "Identifier" &&
        node.object.name === "Reflect" &&
        node.property.type === "Identifier" &&
        node.property.name === "apply" &&
        node.computed === false
    );
}
 
/**
 * Checks whether or not a node is `Array.from`.
 * @param {ASTNode} node - A node to check.
 * @returns {boolean} Whether or not the node is a `Array.from`.
 */
function isArrayFromMethod(node) {
    return (
        node.type === "MemberExpression" &&
        node.object.type === "Identifier" &&
        arrayOrTypedArrayPattern.test(node.object.name) &&
        node.property.type === "Identifier" &&
        node.property.name === "from" &&
        node.computed === false
    );
}
 
/**
 * Checks whether or not a node is a method which has `thisArg`.
 * @param {ASTNode} node - A node to check.
 * @returns {boolean} Whether or not the node is a method which has `thisArg`.
 */
function isMethodWhichHasThisArg(node) {
    while (node) {
        if (node.type === "Identifier") {
            return arrayMethodPattern.test(node.name);
        }
        if (node.type === "MemberExpression" && !node.computed) {
            node = node.property;
            continue;
        }
 
        break;
    }
 
    return false;
}
 
/**
 * Creates the negate function of the given function.
 * @param {Function} f - The function to negate.
 * @returns {Function} Negated function.
 */
function negate(f) {
    return token => !f(token);
}
 
/**
 * Checks whether or not a node has a `@this` tag in its comments.
 * @param {ASTNode} node - A node to check.
 * @param {SourceCode} sourceCode - A SourceCode instance to get comments.
 * @returns {boolean} Whether or not the node has a `@this` tag in its comments.
 */
function hasJSDocThisTag(node, sourceCode) {
    const jsdocComment = sourceCode.getJSDocComment(node);
 
    if (jsdocComment && thisTagPattern.test(jsdocComment.value)) {
        return true;
    }
 
    // Checks `@this` in its leading comments for callbacks,
    // because callbacks don't have its JSDoc comment.
    // e.g.
    //     sinon.test(/* @this sinon.Sandbox */function() { this.spy(); });
    return sourceCode.getComments(node).leading.some(comment => thisTagPattern.test(comment.value));
}
 
/**
 * Determines if a node is surrounded by parentheses.
 * @param {SourceCode} sourceCode The ESLint source code object
 * @param {ASTNode} node The node to be checked.
 * @returns {boolean} True if the node is parenthesised.
 * @private
 */
function isParenthesised(sourceCode, node) {
    const previousToken = sourceCode.getTokenBefore(node),
        nextToken = sourceCode.getTokenAfter(node);
 
    return Boolean(previousToken && nextToken) &&
        previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
        nextToken.value === ")" && nextToken.range[0] >= node.range[1];
}
 
/**
 * Checks if the given token is an arrow token or not.
 *
 * @param {Token} token - The token to check.
 * @returns {boolean} `true` if the token is an arrow token.
 */
function isArrowToken(token) {
    return token.value === "=>" && token.type === "Punctuator";
}
 
/**
 * Checks if the given token is a comma token or not.
 *
 * @param {Token} token - The token to check.
 * @returns {boolean} `true` if the token is a comma token.
 */
function isCommaToken(token) {
    return token.value === "," && token.type === "Punctuator";
}
 
/**
 * Checks if the given token is a semicolon token or not.
 *
 * @param {Token} token - The token to check.
 * @returns {boolean} `true` if the token is a semicolon token.
 */
function isSemicolonToken(token) {
    return token.value === ";" && token.type === "Punctuator";
}
 
/**
 * Checks if the given token is a colon token or not.
 *
 * @param {Token} token - The token to check.
 * @returns {boolean} `true` if the token is a colon token.
 */
function isColonToken(token) {
    return token.value === ":" && token.type === "Punctuator";
}
 
/**
 * Checks if the given token is an opening parenthesis token or not.
 *
 * @param {Token} token - The token to check.
 * @returns {boolean} `true` if the token is an opening parenthesis token.
 */
function isOpeningParenToken(token) {
    return token.value === "(" && token.type === "Punctuator";
}
 
/**
 * Checks if the given token is a closing parenthesis token or not.
 *
 * @param {Token} token - The token to check.
 * @returns {boolean} `true` if the token is a closing parenthesis token.
 */
function isClosingParenToken(token) {
    return token.value === ")" && token.type === "Punctuator";
}
 
/**
 * Checks if the given token is an opening square bracket token or not.
 *
 * @param {Token} token - The token to check.
 * @returns {boolean} `true` if the token is an opening square bracket token.
 */
function isOpeningBracketToken(token) {
    return token.value === "[" && token.type === "Punctuator";
}
 
/**
 * Checks if the given token is a closing square bracket token or not.
 *
 * @param {Token} token - The token to check.
 * @returns {boolean} `true` if the token is a closing square bracket token.
 */
function isClosingBracketToken(token) {
    return token.value === "]" && token.type === "Punctuator";
}
 
/**
 * Checks if the given token is an opening brace token or not.
 *
 * @param {Token} token - The token to check.
 * @returns {boolean} `true` if the token is an opening brace token.
 */
function isOpeningBraceToken(token) {
    return token.value === "{" && token.type === "Punctuator";
}
 
/**
 * Checks if the given token is a closing brace token or not.
 *
 * @param {Token} token - The token to check.
 * @returns {boolean} `true` if the token is a closing brace token.
 */
function isClosingBraceToken(token) {
    return token.value === "}" && token.type === "Punctuator";
}
 
/**
 * Checks if the given token is a comment token or not.
 *
 * @param {Token} token - The token to check.
 * @returns {boolean} `true` if the token is a comment token.
 */
function isCommentToken(token) {
    return token.type === "Line" || token.type === "Block" || token.type === "Shebang";
}
 
/**
 * Checks if the given token is a keyword token or not.
 *
 * @param {Token} token - The token to check.
 * @returns {boolean} `true` if the token is a keyword token.
 */
function isKeywordToken(token) {
    return token.type === "Keyword";
}
 
/**
 * Gets the `(` token of the given function node.
 *
 * @param {ASTNode} node - The function node to get.
 * @param {SourceCode} sourceCode - The source code object to get tokens.
 * @returns {Token} `(` token.
 */
function getOpeningParenOfParams(node, sourceCode) {
    return node.id
        ? sourceCode.getTokenAfter(node.id, isOpeningParenToken)
        : sourceCode.getFirstToken(node, isOpeningParenToken);
}
 
/**
 * Creates a version of the LINEBREAK_MATCHER regex with the global flag.
 * Global regexes are mutable, so this needs to be a function instead of a constant.
 * @returns {RegExp} A global regular expression that matches line terminators
 */
function createGlobalLinebreakMatcher() {
    return new RegExp(LINEBREAK_MATCHER.source, "g");
}
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
module.exports = {
    COMMENTS_IGNORE_PATTERN,
    LINEBREAKS,
    LINEBREAK_MATCHER,
    STATEMENT_LIST_PARENTS,
 
    /**
     * Determines whether two adjacent tokens are on the same line.
     * @param {Object} left - The left token object.
     * @param {Object} right - The right token object.
     * @returns {boolean} Whether or not the tokens are on the same line.
     * @public
     */
    isTokenOnSameLine(left, right) {
        return left.loc.end.line === right.loc.start.line;
    },
 
    isNullOrUndefined,
    isCallee,
    isES5Constructor,
    getUpperFunction,
    isFunction,
    isLoop,
    isInLoop,
    isArrayFromMethod,
    isParenthesised,
    createGlobalLinebreakMatcher,
 
    isArrowToken,
    isClosingBraceToken,
    isClosingBracketToken,
    isClosingParenToken,
    isColonToken,
    isCommaToken,
    isCommentToken,
    isKeywordToken,
    isNotClosingBraceToken: negate(isClosingBraceToken),
    isNotClosingBracketToken: negate(isClosingBracketToken),
    isNotClosingParenToken: negate(isClosingParenToken),
    isNotColonToken: negate(isColonToken),
    isNotCommaToken: negate(isCommaToken),
    isNotOpeningBraceToken: negate(isOpeningBraceToken),
    isNotOpeningBracketToken: negate(isOpeningBracketToken),
    isNotOpeningParenToken: negate(isOpeningParenToken),
    isNotSemicolonToken: negate(isSemicolonToken),
    isOpeningBraceToken,
    isOpeningBracketToken,
    isOpeningParenToken,
    isSemicolonToken,
 
    /**
     * Checks whether or not a given node is a string literal.
     * @param {ASTNode} node - A node to check.
     * @returns {boolean} `true` if the node is a string literal.
     */
    isStringLiteral(node) {
        return (
            (node.type === "Literal" && typeof node.value === "string") ||
            node.type === "TemplateLiteral"
        );
    },
 
    /**
     * Checks whether a given node is a breakable statement or not.
     * The node is breakable if the node is one of the following type:
     *
     * - DoWhileStatement
     * - ForInStatement
     * - ForOfStatement
     * - ForStatement
     * - SwitchStatement
     * - WhileStatement
     *
     * @param {ASTNode} node - A node to check.
     * @returns {boolean} `true` if the node is breakable.
     */
    isBreakableStatement(node) {
        return breakableTypePattern.test(node.type);
    },
 
    /**
     * Gets the label if the parent node of a given node is a LabeledStatement.
     *
     * @param {ASTNode} node - A node to get.
     * @returns {string|null} The label or `null`.
     */
    getLabel(node) {
        if (node.parent.type === "LabeledStatement") {
            return node.parent.label.name;
        }
        return null;
    },
 
    /**
     * Gets references which are non initializer and writable.
     * @param {Reference[]} references - An array of references.
     * @returns {Reference[]} An array of only references which are non initializer and writable.
     * @public
     */
    getModifyingReferences(references) {
        return references.filter(isModifyingReference);
    },
 
    /**
     * Validate that a string passed in is surrounded by the specified character
     * @param  {string} val The text to check.
     * @param  {string} character The character to see if it's surrounded by.
     * @returns {boolean} True if the text is surrounded by the character, false if not.
     * @private
     */
    isSurroundedBy(val, character) {
        return val[0] === character && val[val.length - 1] === character;
    },
 
    /**
     * Returns whether the provided node is an ESLint directive comment or not
     * @param {LineComment|BlockComment} node The node to be checked
     * @returns {boolean} `true` if the node is an ESLint directive comment
     */
    isDirectiveComment(node) {
        const comment = node.value.trim();
 
        return (
            node.type === "Line" && comment.indexOf("eslint-") === 0 ||
            node.type === "Block" && (
                comment.indexOf("global ") === 0 ||
                comment.indexOf("eslint ") === 0 ||
                comment.indexOf("eslint-") === 0
            )
        );
    },
 
    /**
     * Gets the trailing statement of a given node.
     *
     *     if (code)
     *         consequent;
     *
     * When taking this `IfStatement`, returns `consequent;` statement.
     *
     * @param {ASTNode} A node to get.
     * @returns {ASTNode|null} The trailing statement's node.
     */
    getTrailingStatement: esutils.ast.trailingStatement,
 
    /**
     * Finds the variable by a given name in a given scope and its upper scopes.
     *
     * @param {escope.Scope} initScope - A scope to start find.
     * @param {string} name - A variable name to find.
     * @returns {escope.Variable|null} A found variable or `null`.
     */
    getVariableByName(initScope, name) {
        let scope = initScope;
 
        while (scope) {
            const variable = scope.set.get(name);
 
            if (variable) {
                return variable;
            }
 
            scope = scope.upper;
        }
 
        return null;
    },
 
    /**
     * Checks whether or not a given function node is the default `this` binding.
     *
     * First, this checks the node:
     *
     * - The function name does not start with uppercase (it's a constructor).
     * - The function does not have a JSDoc comment that has a @this tag.
     *
     * Next, this checks the location of the node.
     * If the location is below, this judges `this` is valid.
     *
     * - The location is not on an object literal.
     * - The location is not assigned to a variable which starts with an uppercase letter.
     * - The location is not on an ES2015 class.
     * - Its `bind`/`call`/`apply` method is not called directly.
     * - The function is not a callback of array methods (such as `.forEach()`) if `thisArg` is given.
     *
     * @param {ASTNode} node - A function node to check.
     * @param {SourceCode} sourceCode - A SourceCode instance to get comments.
     * @returns {boolean} The function node is the default `this` binding.
     */
    isDefaultThisBinding(node, sourceCode) {
        if (isES5Constructor(node) || hasJSDocThisTag(node, sourceCode)) {
            return false;
        }
        const isAnonymous = node.id === null;
 
        while (node) {
            const parent = node.parent;
 
            switch (parent.type) {
 
                /*
                 * Looks up the destination.
                 * e.g., obj.foo = nativeFoo || function foo() { ... };
                 */
                case "LogicalExpression":
                case "ConditionalExpression":
                    node = parent;
                    break;
 
                // If the upper function is IIFE, checks the destination of the return value.
                // e.g.
                //   obj.foo = (function() {
                //     // setup...
                //     return function foo() { ... };
                //   })();
                case "ReturnStatement": {
                    const func = getUpperFunction(parent);
 
                    if (func === null || !isCallee(func)) {
                        return true;
                    }
                    node = func.parent;
                    break;
                }
 
                // e.g.
                //   var obj = { foo() { ... } };
                //   var obj = { foo: function() { ... } };
                //   class A { constructor() { ... } }
                //   class A { foo() { ... } }
                //   class A { get foo() { ... } }
                //   class A { set foo() { ... } }
                //   class A { static foo() { ... } }
                case "Property":
                case "MethodDefinition":
                    return parent.value !== node;
 
                // e.g.
                //   obj.foo = function foo() { ... };
                //   Foo = function() { ... };
                //   [obj.foo = function foo() { ... }] = a;
                //   [Foo = function() { ... }] = a;
                case "AssignmentExpression":
                case "AssignmentPattern":
                    if (parent.right === node) {
                        if (parent.left.type === "MemberExpression") {
                            return false;
                        }
                        if (isAnonymous &&
                            parent.left.type === "Identifier" &&
                            startsWithUpperCase(parent.left.name)
                        ) {
                            return false;
                        }
                    }
                    return true;
 
                // e.g.
                //   var Foo = function() { ... };
                case "VariableDeclarator":
                    return !(
                        isAnonymous &&
                        parent.init === node &&
                        parent.id.type === "Identifier" &&
                        startsWithUpperCase(parent.id.name)
                    );
 
                // e.g.
                //   var foo = function foo() { ... }.bind(obj);
                //   (function foo() { ... }).call(obj);
                //   (function foo() { ... }).apply(obj, []);
                case "MemberExpression":
                    return (
                        parent.object !== node ||
                        parent.property.type !== "Identifier" ||
                        !bindOrCallOrApplyPattern.test(parent.property.name) ||
                        !isCallee(parent) ||
                        parent.parent.arguments.length === 0 ||
                        isNullOrUndefined(parent.parent.arguments[0])
                    );
 
                // e.g.
                //   Reflect.apply(function() {}, obj, []);
                //   Array.from([], function() {}, obj);
                //   list.forEach(function() {}, obj);
                case "CallExpression":
                    if (isReflectApply(parent.callee)) {
                        return (
                            parent.arguments.length !== 3 ||
                            parent.arguments[0] !== node ||
                            isNullOrUndefined(parent.arguments[1])
                        );
                    }
                    if (isArrayFromMethod(parent.callee)) {
                        return (
                            parent.arguments.length !== 3 ||
                            parent.arguments[1] !== node ||
                            isNullOrUndefined(parent.arguments[2])
                        );
                    }
                    if (isMethodWhichHasThisArg(parent.callee)) {
                        return (
                            parent.arguments.length !== 2 ||
                            parent.arguments[0] !== node ||
                            isNullOrUndefined(parent.arguments[1])
                        );
                    }
                    return true;
 
                // Otherwise `this` is default.
                default:
                    return true;
            }
        }
 
        /* istanbul ignore next */
        return true;
    },
 
    /**
     * Get the precedence level based on the node type
     * @param {ASTNode} node node to evaluate
     * @returns {int} precedence level
     * @private
     */
    getPrecedence(node) {
        switch (node.type) {
            case "SequenceExpression":
                return 0;
 
            case "AssignmentExpression":
            case "ArrowFunctionExpression":
            case "YieldExpression":
                return 1;
 
            case "ConditionalExpression":
                return 3;
 
            case "LogicalExpression":
                switch (node.operator) {
                    case "||":
                        return 4;
                    case "&&":
                        return 5;
 
                    // no default
                }
 
                /* falls through */
 
            case "BinaryExpression":
 
                switch (node.operator) {
                    case "|":
                        return 6;
                    case "^":
                        return 7;
                    case "&":
                        return 8;
                    case "==":
                    case "!=":
                    case "===":
                    case "!==":
                        return 9;
                    case "<":
                    case "<=":
                    case ">":
                    case ">=":
                    case "in":
                    case "instanceof":
                        return 10;
                    case "<<":
                    case ">>":
                    case ">>>":
                        return 11;
                    case "+":
                    case "-":
                        return 12;
                    case "*":
                    case "/":
                    case "%":
                        return 13;
                    case "**":
                        return 15;
 
                    // no default
                }
 
                /* falls through */
 
            case "UnaryExpression":
            case "AwaitExpression":
                return 16;
 
            case "UpdateExpression":
                return 17;
 
            case "CallExpression":
 
                // IIFE is allowed to have parens in any position (#655)
                if (node.callee.type === "FunctionExpression") {
                    return -1;
                }
                return 18;
 
            case "NewExpression":
                return 19;
 
            // no default
        }
        return 20;
    },
 
    /**
     * Checks whether the given node is an empty block node or not.
     *
     * @param {ASTNode|null} node - The node to check.
     * @returns {boolean} `true` if the node is an empty block.
     */
    isEmptyBlock(node) {
        return Boolean(node && node.type === "BlockStatement" && node.body.length === 0);
    },
 
    /**
     * Checks whether the given node is an empty function node or not.
     *
     * @param {ASTNode|null} node - The node to check.
     * @returns {boolean} `true` if the node is an empty function.
     */
    isEmptyFunction(node) {
        return isFunction(node) && module.exports.isEmptyBlock(node.body);
    },
 
    /**
     * Gets the property name of a given node.
     * The node can be a MemberExpression, a Property, or a MethodDefinition.
     *
     * If the name is dynamic, this returns `null`.
     *
     * For examples:
     *
     *     a.b           // => "b"
     *     a["b"]        // => "b"
     *     a['b']        // => "b"
     *     a[`b`]        // => "b"
     *     a[100]        // => "100"
     *     a[b]          // => null
     *     a["a" + "b"]  // => null
     *     a[tag`b`]     // => null
     *     a[`${b}`]     // => null
     *
     *     let a = {b: 1}            // => "b"
     *     let a = {["b"]: 1}        // => "b"
     *     let a = {['b']: 1}        // => "b"
     *     let a = {[`b`]: 1}        // => "b"
     *     let a = {[100]: 1}        // => "100"
     *     let a = {[b]: 1}          // => null
     *     let a = {["a" + "b"]: 1}  // => null
     *     let a = {[tag`b`]: 1}     // => null
     *     let a = {[`${b}`]: 1}     // => null
     *
     * @param {ASTNode} node - The node to get.
     * @returns {string|null} The property name if static. Otherwise, null.
     */
    getStaticPropertyName(node) {
        let prop;
 
        switch (node && node.type) {
            case "Property":
            case "MethodDefinition":
                prop = node.key;
                break;
 
            case "MemberExpression":
                prop = node.property;
                break;
 
            // no default
        }
 
        switch (prop && prop.type) {
            case "Literal":
                return String(prop.value);
 
            case "TemplateLiteral":
                if (prop.expressions.length === 0 && prop.quasis.length === 1) {
                    return prop.quasis[0].value.cooked;
                }
                break;
 
            case "Identifier":
                if (!node.computed) {
                    return prop.name;
                }
                break;
 
            // no default
        }
 
        return null;
    },
 
    /**
     * Get directives from directive prologue of a Program or Function node.
     * @param {ASTNode} node - The node to check.
     * @returns {ASTNode[]} The directives found in the directive prologue.
     */
    getDirectivePrologue(node) {
        const directives = [];
 
        // Directive prologues only occur at the top of files or functions.
        if (
            node.type === "Program" ||
            node.type === "FunctionDeclaration" ||
            node.type === "FunctionExpression" ||
 
            // Do not check arrow functions with implicit return.
            // `() => "use strict";` returns the string `"use strict"`.
            (node.type === "ArrowFunctionExpression" && node.body.type === "BlockStatement")
        ) {
            const statements = node.type === "Program" ? node.body : node.body.body;
 
            for (const statement of statements) {
                if (
                    statement.type === "ExpressionStatement" &&
                    statement.expression.type === "Literal"
                ) {
                    directives.push(statement);
                } else {
                    break;
                }
            }
        }
 
        return directives;
    },
 
 
    /**
     * Determines whether this node is a decimal integer literal. If a node is a decimal integer literal, a dot added
     after the node will be parsed as a decimal point, rather than a property-access dot.
     * @param {ASTNode} node - The node to check.
     * @returns {boolean} `true` if this node is a decimal integer.
     * @example
     *
     * 5       // true
     * 5.      // false
     * 5.0     // false
     * 05      // false
     * 0x5     // false
     * 0b101   // false
     * 0o5     // false
     * 5e0     // false
     * '5'     // false
     */
    isDecimalInteger(node) {
        return node.type === "Literal" && typeof node.value === "number" && /^(0|[1-9]\d*)$/.test(node.raw);
    },
 
    /**
     * Gets the name and kind of the given function node.
     *
     * - `function foo() {}`  .................... `function 'foo'`
     * - `(function foo() {})`  .................. `function 'foo'`
     * - `(function() {})`  ...................... `function`
     * - `function* foo() {}`  ................... `generator function 'foo'`
     * - `(function* foo() {})`  ................. `generator function 'foo'`
     * - `(function*() {})`  ..................... `generator function`
     * - `() => {}`  ............................. `arrow function`
     * - `async () => {}`  ....................... `async arrow function`
     * - `({ foo: function foo() {} })`  ......... `method 'foo'`
     * - `({ foo: function() {} })`  ............. `method 'foo'`
     * - `({ ['foo']: function() {} })`  ......... `method 'foo'`
     * - `({ [foo]: function() {} })`  ........... `method`
     * - `({ foo() {} })`  ....................... `method 'foo'`
     * - `({ foo: function* foo() {} })`  ........ `generator method 'foo'`
     * - `({ foo: function*() {} })`  ............ `generator method 'foo'`
     * - `({ ['foo']: function*() {} })`  ........ `generator method 'foo'`
     * - `({ [foo]: function*() {} })`  .......... `generator method`
     * - `({ *foo() {} })`  ...................... `generator method 'foo'`
     * - `({ foo: async function foo() {} })`  ... `async method 'foo'`
     * - `({ foo: async function() {} })`  ....... `async method 'foo'`
     * - `({ ['foo']: async function() {} })`  ... `async method 'foo'`
     * - `({ [foo]: async function() {} })`  ..... `async method`
     * - `({ async foo() {} })`  ................. `async method 'foo'`
     * - `({ get foo() {} })`  ................... `getter 'foo'`
     * - `({ set foo(a) {} })`  .................. `setter 'foo'`
     * - `class A { constructor() {} }`  ......... `constructor`
     * - `class A { foo() {} }`  ................. `method 'foo'`
     * - `class A { *foo() {} }`  ................ `generator method 'foo'`
     * - `class A { async foo() {} }`  ........... `async method 'foo'`
     * - `class A { ['foo']() {} }`  ............. `method 'foo'`
     * - `class A { *['foo']() {} }`  ............ `generator method 'foo'`
     * - `class A { async ['foo']() {} }`  ....... `async method 'foo'`
     * - `class A { [foo]() {} }`  ............... `method`
     * - `class A { *[foo]() {} }`  .............. `generator method`
     * - `class A { async [foo]() {} }`  ......... `async method`
     * - `class A { get foo() {} }`  ............. `getter 'foo'`
     * - `class A { set foo(a) {} }`  ............ `setter 'foo'`
     * - `class A { static foo() {} }`  .......... `static method 'foo'`
     * - `class A { static *foo() {} }`  ......... `static generator method 'foo'`
     * - `class A { static async foo() {} }`  .... `static async method 'foo'`
     * - `class A { static get foo() {} }`  ...... `static getter 'foo'`
     * - `class A { static set foo(a) {} }`  ..... `static setter 'foo'`
     *
     * @param {ASTNode} node - The function node to get.
     * @returns {string} The name and kind of the function node.
     */
    getFunctionNameWithKind(node) {
        const parent = node.parent;
        const tokens = [];
 
        if (parent.type === "MethodDefinition" && parent.static) {
            tokens.push("static");
        }
        if (node.async) {
            tokens.push("async");
        }
        if (node.generator) {
            tokens.push("generator");
        }
 
        if (node.type === "ArrowFunctionExpression") {
            tokens.push("arrow", "function");
        } else if (parent.type === "Property" || parent.type === "MethodDefinition") {
            if (parent.kind === "constructor") {
                return "constructor";
            } else if (parent.kind === "get") {
                tokens.push("getter");
            } else if (parent.kind === "set") {
                tokens.push("setter");
            } else {
                tokens.push("method");
            }
        } else {
            tokens.push("function");
        }
 
        if (node.id) {
            tokens.push(`'${node.id.name}'`);
        } else {
            const name = module.exports.getStaticPropertyName(parent);
 
            if (name) {
                tokens.push(`'${name}'`);
            }
        }
 
        return tokens.join(" ");
    },
 
    /**
     * Gets the location of the given function node for reporting.
     *
     * - `function foo() {}`
     *    ^^^^^^^^^^^^
     * - `(function foo() {})`
     *     ^^^^^^^^^^^^
     * - `(function() {})`
     *     ^^^^^^^^
     * - `function* foo() {}`
     *    ^^^^^^^^^^^^^
     * - `(function* foo() {})`
     *     ^^^^^^^^^^^^^
     * - `(function*() {})`
     *     ^^^^^^^^^
     * - `() => {}`
     *       ^^
     * - `async () => {}`
     *             ^^
     * - `({ foo: function foo() {} })`
     *       ^^^^^^^^^^^^^^^^^
     * - `({ foo: function() {} })`
     *       ^^^^^^^^^^^^^
     * - `({ ['foo']: function() {} })`
     *       ^^^^^^^^^^^^^^^^^
     * - `({ [foo]: function() {} })`
     *       ^^^^^^^^^^^^^^^
     * - `({ foo() {} })`
     *       ^^^
     * - `({ foo: function* foo() {} })`
     *       ^^^^^^^^^^^^^^^^^^
     * - `({ foo: function*() {} })`
     *       ^^^^^^^^^^^^^^
     * - `({ ['foo']: function*() {} })`
     *       ^^^^^^^^^^^^^^^^^^
     * - `({ [foo]: function*() {} })`
     *       ^^^^^^^^^^^^^^^^
     * - `({ *foo() {} })`
     *       ^^^^
     * - `({ foo: async function foo() {} })`
     *       ^^^^^^^^^^^^^^^^^^^^^^^
     * - `({ foo: async function() {} })`
     *       ^^^^^^^^^^^^^^^^^^^
     * - `({ ['foo']: async function() {} })`
     *       ^^^^^^^^^^^^^^^^^^^^^^^
     * - `({ [foo]: async function() {} })`
     *       ^^^^^^^^^^^^^^^^^^^^^
     * - `({ async foo() {} })`
     *       ^^^^^^^^^
     * - `({ get foo() {} })`
     *       ^^^^^^^
     * - `({ set foo(a) {} })`
     *       ^^^^^^^
     * - `class A { constructor() {} }`
     *              ^^^^^^^^^^^
     * - `class A { foo() {} }`
     *              ^^^
     * - `class A { *foo() {} }`
     *              ^^^^
     * - `class A { async foo() {} }`
     *              ^^^^^^^^^
     * - `class A { ['foo']() {} }`
     *              ^^^^^^^
     * - `class A { *['foo']() {} }`
     *              ^^^^^^^^
     * - `class A { async ['foo']() {} }`
     *              ^^^^^^^^^^^^^
     * - `class A { [foo]() {} }`
     *              ^^^^^
     * - `class A { *[foo]() {} }`
     *              ^^^^^^
     * - `class A { async [foo]() {} }`
     *              ^^^^^^^^^^^
     * - `class A { get foo() {} }`
     *              ^^^^^^^
     * - `class A { set foo(a) {} }`
     *              ^^^^^^^
     * - `class A { static foo() {} }`
     *              ^^^^^^^^^^
     * - `class A { static *foo() {} }`
     *              ^^^^^^^^^^^
     * - `class A { static async foo() {} }`
     *              ^^^^^^^^^^^^^^^^
     * - `class A { static get foo() {} }`
     *              ^^^^^^^^^^^^^^
     * - `class A { static set foo(a) {} }`
     *              ^^^^^^^^^^^^^^
     *
     * @param {ASTNode} node - The function node to get.
     * @param {SourceCode} sourceCode - The source code object to get tokens.
     * @returns {string} The location of the function node for reporting.
     */
    getFunctionHeadLoc(node, sourceCode) {
        const parent = node.parent;
        let start = null;
        let end = null;
 
        if (node.type === "ArrowFunctionExpression") {
            const arrowToken = sourceCode.getTokenBefore(node.body, isArrowToken);
 
            start = arrowToken.loc.start;
            end = arrowToken.loc.end;
        } else if (parent.type === "Property" || parent.type === "MethodDefinition") {
            start = parent.loc.start;
            end = getOpeningParenOfParams(node, sourceCode).loc.start;
        } else {
            start = node.loc.start;
            end = getOpeningParenOfParams(node, sourceCode).loc.start;
        }
 
        return {
            start: Object.assign({}, start),
            end: Object.assign({}, end)
        };
    },
 
    /**
    * Gets the parenthesized text of a node. This is similar to sourceCode.getText(node), but it also includes any parentheses
    * surrounding the node.
    * @param {SourceCode} sourceCode The source code object
    * @param {ASTNode} node An expression node
    * @returns {string} The text representing the node, with all surrounding parentheses included
    */
    getParenthesisedText(sourceCode, node) {
        let leftToken = sourceCode.getFirstToken(node);
        let rightToken = sourceCode.getLastToken(node);
 
        while (
            sourceCode.getTokenBefore(leftToken) &&
            sourceCode.getTokenBefore(leftToken).type === "Punctuator" &&
            sourceCode.getTokenBefore(leftToken).value === "(" &&
            sourceCode.getTokenAfter(rightToken) &&
            sourceCode.getTokenAfter(rightToken).type === "Punctuator" &&
            sourceCode.getTokenAfter(rightToken).value === ")"
        ) {
            leftToken = sourceCode.getTokenBefore(leftToken);
            rightToken = sourceCode.getTokenAfter(rightToken);
        }
 
        return sourceCode.getText().slice(leftToken.range[0], rightToken.range[1]);
    },
 
    /*
     * Determine if a node has a possiblity to be an Error object
     * @param  {ASTNode} node  ASTNode to check
     * @returns {boolean} True if there is a chance it contains an Error obj
     */
    couldBeError(node) {
        switch (node.type) {
            case "Identifier":
            case "CallExpression":
            case "NewExpression":
            case "MemberExpression":
            case "TaggedTemplateExpression":
            case "YieldExpression":
            case "AwaitExpression":
                return true; // possibly an error object.
 
            case "AssignmentExpression":
                return module.exports.couldBeError(node.right);
 
            case "SequenceExpression": {
                const exprs = node.expressions;
 
                return exprs.length !== 0 && module.exports.couldBeError(exprs[exprs.length - 1]);
            }
 
            case "LogicalExpression":
                return module.exports.couldBeError(node.left) || module.exports.couldBeError(node.right);
 
            case "ConditionalExpression":
                return module.exports.couldBeError(node.consequent) || module.exports.couldBeError(node.alternate);
 
            default:
                return false;
        }
    },
 
    /**
     * Determines whether the given node is a `null` literal.
     * @param {ASTNode} node The node to check
     * @returns {boolean} `true` if the node is a `null` literal
     */
    isNullLiteral(node) {
 
        /*
         * Checking `node.value === null` does not guarantee that a literal is a null literal.
         * When parsing values that cannot be represented in the current environment (e.g. unicode
         * regexes in Node 4), `node.value` is set to `null` because it wouldn't be possible to
         * set `node.value` to a unicode regex. To make sure a literal is actually `null`, check
         * `node.regex` instead. Also see: https://github.com/eslint/eslint/issues/8020
         */
        return node.type === "Literal" && node.value === null && !node.regex;
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/cli-engine.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/cli-engine.js

Statements: 9.95% (20 / 201)      Branches: 0% (0 / 102)      Functions: 0% (0 / 21)      Lines: 10% (20 / 200)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799                                  1                                 1                                                                                                                 1                                       1                                               1                                                                                                                                           1                                                                                                                                                                                           1                               1                                                                         1                               1                             1                                                                                                               1                                                                                             1                                                                             1                                                 1           1                                                                                 1                                                             1                                                                                                                                                                                                                                                                                                                                           1   1    
/**
 * @fileoverview Main CLI object.
 * @author Nicholas C. Zakas
 */
 
"use strict";
 
/*
 * The CLI object should *not* call process.exit() directly. It should only return
 * exit codes. This allows other programs to use the CLI object and still control
 * when the program exits.
 */
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const fs = require("fs"),
    path = require("path"),
    rules = require("./rules"),
    eslint = require("./eslint"),
    defaultOptions = require("../conf/cli-options"),
    IgnoredPaths = require("./ignored-paths"),
    Config = require("./config"),
    Plugins = require("./config/plugins"),
    fileEntryCache = require("file-entry-cache"),
    globUtil = require("./util/glob-util"),
    SourceCodeFixer = require("./util/source-code-fixer"),
    validator = require("./config/config-validator"),
    stringify = require("json-stable-stringify"),
    hash = require("./util/hash"),
 
    pkg = require("../package.json");
 
const debug = require("debug")("eslint:cli-engine");
 
//------------------------------------------------------------------------------
// Typedefs
//------------------------------------------------------------------------------
 
/**
 * The options to configure a CLI engine with.
 * @typedef {Object} CLIEngineOptions
 * @property {boolean} allowInlineConfig Enable or disable inline configuration comments.
 * @property {boolean|Object} baseConfig Base config object. True enables recommend rules and environments.
 * @property {boolean} cache Enable result caching.
 * @property {string} cacheLocation The cache file to use instead of .eslintcache.
 * @property {string} configFile The configuration file to use.
 * @property {string} cwd The value to use for the current working directory.
 * @property {string[]} envs An array of environments to load.
 * @property {string[]} extensions An array of file extensions to check.
 * @property {boolean} fix Execute in autofix mode.
 * @property {string[]} globals An array of global variables to declare.
 * @property {boolean} ignore False disables use of .eslintignore.
 * @property {string} ignorePath The ignore file to use instead of .eslintignore.
 * @property {string} ignorePattern A glob pattern of files to ignore.
 * @property {boolean} useEslintrc False disables looking for .eslintrc
 * @property {string} parser The name of the parser to use.
 * @property {Object} parserOptions An object of parserOption settings to use.
 * @property {string[]} plugins An array of plugins to load.
 * @property {Object<string,*>} rules An object of rules to use.
 * @property {string[]} rulePaths An array of directories to load custom rules from.
 */
 
/**
 * A linting warning or error.
 * @typedef {Object} LintMessage
 * @property {string} message The message to display to the user.
 */
 
/**
 * A linting result.
 * @typedef {Object} LintResult
 * @property {string} filePath The path to the file that was linted.
 * @property {LintMessage[]} messages All of the messages for the result.
 * @property {number} errorCount Number or errors for the result.
 * @property {number} warningCount Number or warnings for the result.
 * @property {string=} [source] The source code of the file that was linted.
 * @property {string=} [output] The source code of the file that was linted, with as many fixes applied as possible.
 */
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * It will calculate the error and warning count for collection of messages per file
 * @param {Object[]} messages - Collection of messages
 * @returns {Object} Contains the stats
 * @private
 */
function calculateStatsPerFile(messages) {
    return messages.reduce((stat, message) => {
        if (message.fatal || message.severity === 2) {
            stat.errorCount++;
        } else {
            stat.warningCount++;
        }
        return stat;
    }, {
        errorCount: 0,
        warningCount: 0
    });
}
 
/**
 * It will calculate the error and warning count for collection of results from all files
 * @param {Object[]} results - Collection of messages from all the files
 * @returns {Object} Contains the stats
 * @private
 */
function calculateStatsPerRun(results) {
    return results.reduce((stat, result) => {
        stat.errorCount += result.errorCount;
        stat.warningCount += result.warningCount;
        return stat;
    }, {
        errorCount: 0,
        warningCount: 0
    });
}
 
/**
 * Performs multiple autofix passes over the text until as many fixes as possible
 * have been applied.
 * @param {string} text The source text to apply fixes to.
 * @param {Object} config The ESLint config object to use.
 * @param {Object} options The ESLint options object to use.
 * @param {string} options.filename The filename from which the text was read.
 * @param {boolean} options.allowInlineConfig Flag indicating if inline comments
 *      should be allowed.
 * @returns {Object} The result of the fix operation as returned from the
 *      SourceCodeFixer.
 * @private
 */
function multipassFix(text, config, options) {
    const MAX_PASSES = 10;
    let messages = [],
        fixedResult,
        fixed = false,
        passNumber = 0;
 
    /**
     * This loop continues until one of the following is true:
     *
     * 1. No more fixes have been applied.
     * 2. Ten passes have been made.
     *
     * That means anytime a fix is successfully applied, there will be another pass.
     * Essentially, guaranteeing a minimum of two passes.
     */
    do {
        passNumber++;
 
        debug(`Linting code for ${options.filename} (pass ${passNumber})`);
        messages = eslint.verify(text, config, options);
 
        debug(`Generating fixed text for ${options.filename} (pass ${passNumber})`);
        fixedResult = SourceCodeFixer.applyFixes(eslint.getSourceCode(), messages);
 
        // stop if there are any syntax errors.
        // 'fixedResult.output' is a empty string.
        if (messages.length === 1 && messages[0].fatal) {
            break;
        }
 
        // keep track if any fixes were ever applied - important for return value
        fixed = fixed || fixedResult.fixed;
 
        // update to use the fixed output instead of the original text
        text = fixedResult.output;
 
    } while (
        fixedResult.fixed &&
        passNumber < MAX_PASSES
    );
 
 
    /*
     * If the last result had fixes, we need to lint again to be sure we have
     * the most up-to-date information.
     */
    if (fixedResult.fixed) {
        fixedResult.messages = eslint.verify(text, config, options);
    }
 
 
    // ensure the last result properly reflects if fixes were done
    fixedResult.fixed = fixed;
    fixedResult.output = text;
 
    return fixedResult;
 
}
 
/**
 * Processes an source code using ESLint.
 * @param {string} text The source code to check.
 * @param {Object} configHelper The configuration options for ESLint.
 * @param {string} filename An optional string representing the texts filename.
 * @param {boolean} fix Indicates if fixes should be processed.
 * @param {boolean} allowInlineConfig Allow/ignore comments that change config.
 * @returns {LintResult} The results for linting on this text.
 * @private
 */
function processText(text, configHelper, filename, fix, allowInlineConfig) {
 
    // clear all existing settings for a new file
    eslint.reset();
 
    let filePath,
        messages,
        fileExtension,
        processor,
        fixedResult;
 
    if (filename) {
        filePath = path.resolve(filename);
        fileExtension = path.extname(filename);
    }
 
    filename = filename || "<text>";
    debug(`Linting ${filename}`);
    const config = configHelper.getConfig(filePath);
 
    if (config.plugins) {
        Plugins.loadAll(config.plugins);
    }
 
    const loadedPlugins = Plugins.getAll();
 
    for (const plugin in loadedPlugins) {
        if (loadedPlugins[plugin].processors && Object.keys(loadedPlugins[plugin].processors).indexOf(fileExtension) >= 0) {
            processor = loadedPlugins[plugin].processors[fileExtension];
            break;
        }
    }
 
    if (processor) {
        debug("Using processor");
        const parsedBlocks = processor.preprocess(text, filename);
        const unprocessedMessages = [];
 
        parsedBlocks.forEach(block => {
            unprocessedMessages.push(eslint.verify(block, config, {
                filename,
                allowInlineConfig
            }));
        });
 
        // TODO(nzakas): Figure out how fixes might work for processors
 
        messages = processor.postprocess(unprocessedMessages, filename);
 
    } else {
 
        if (fix) {
            fixedResult = multipassFix(text, config, {
                filename,
                allowInlineConfig
            });
            messages = fixedResult.messages;
        } else {
            messages = eslint.verify(text, config, {
                filename,
                allowInlineConfig
            });
        }
    }
 
    const stats = calculateStatsPerFile(messages);
 
    const result = {
        filePath: filename,
        messages,
        errorCount: stats.errorCount,
        warningCount: stats.warningCount
    };
 
    if (fixedResult && fixedResult.fixed) {
        result.output = fixedResult.output;
    }
 
    if (result.errorCount + result.warningCount > 0 && typeof result.output === "undefined") {
        result.source = text;
    }
 
    return result;
}
 
/**
 * Processes an individual file using ESLint. Files used here are known to
 * exist, so no need to check that here.
 * @param {string} filename The filename of the file being checked.
 * @param {Object} configHelper The configuration options for ESLint.
 * @param {Object} options The CLIEngine options object.
 * @returns {LintResult} The results for linting on this file.
 * @private
 */
function processFile(filename, configHelper, options) {
 
    const text = fs.readFileSync(path.resolve(filename), "utf8"),
        result = processText(text, configHelper, filename, options.fix, options.allowInlineConfig);
 
    return result;
 
}
 
/**
 * Returns result with warning by ignore settings
 * @param {string} filePath - File path of checked code
 * @param {string} baseDir  - Absolute path of base directory
 * @returns {LintResult} Result with single warning
 * @private
 */
function createIgnoreResult(filePath, baseDir) {
    let message;
    const isHidden = /^\./.test(path.basename(filePath));
    const isInNodeModules = baseDir && /^node_modules/.test(path.relative(baseDir, filePath));
    const isInBowerComponents = baseDir && /^bower_components/.test(path.relative(baseDir, filePath));
 
    if (isHidden) {
        message = "File ignored by default.  Use a negated ignore pattern (like \"--ignore-pattern '!<relative/path/to/filename>'\") to override.";
    } else if (isInNodeModules) {
        message = "File ignored by default. Use \"--ignore-pattern '!node_modules/*'\" to override.";
    } else if (isInBowerComponents) {
        message = "File ignored by default. Use \"--ignore-pattern '!bower_components/*'\" to override.";
    } else {
        message = "File ignored because of a matching ignore pattern. Use \"--no-ignore\" to override.";
    }
 
    return {
        filePath: path.resolve(filePath),
        messages: [
            {
                fatal: false,
                severity: 1,
                message
            }
        ],
        errorCount: 0,
        warningCount: 1
    };
}
 
 
/**
 * Checks if the given message is an error message.
 * @param {Object} message The message to check.
 * @returns {boolean} Whether or not the message is an error message.
 * @private
 */
function isErrorMessage(message) {
    return message.severity === 2;
}
 
 
/**
 * return the cacheFile to be used by eslint, based on whether the provided parameter is
 * a directory or looks like a directory (ends in `path.sep`), in which case the file
 * name will be the `cacheFile/.cache_hashOfCWD`
 *
 * if cacheFile points to a file or looks like a file then in will just use that file
 *
 * @param {string} cacheFile The name of file to be used to store the cache
 * @param {string} cwd Current working directory
 * @returns {string} the resolved path to the cache file
 */
function getCacheFile(cacheFile, cwd) {
 
    /*
     * make sure the path separators are normalized for the environment/os
     * keeping the trailing path separator if present
     */
    cacheFile = path.normalize(cacheFile);
 
    const resolvedCacheFile = path.resolve(cwd, cacheFile);
    const looksLikeADirectory = cacheFile[cacheFile.length - 1 ] === path.sep;
 
    /**
     * return the name for the cache file in case the provided parameter is a directory
     * @returns {string} the resolved path to the cacheFile
     */
    function getCacheFileForDirectory() {
        return path.join(resolvedCacheFile, `.cache_${hash(cwd)}`);
    }
 
    let fileStats;
 
    try {
        fileStats = fs.lstatSync(resolvedCacheFile);
    } catch (ex) {
        fileStats = null;
    }
 
 
    /*
     * in case the file exists we need to verify if the provided path
     * is a directory or a file. If it is a directory we want to create a file
     * inside that directory
     */
    if (fileStats) {
 
        /*
         * is a directory or is a file, but the original file the user provided
         * looks like a directory but `path.resolve` removed the `last path.sep`
         * so we need to still treat this like a directory
         */
        if (fileStats.isDirectory() || looksLikeADirectory) {
            return getCacheFileForDirectory();
        }
 
        // is file so just use that file
        return resolvedCacheFile;
    }
 
    /*
     * here we known the file or directory doesn't exist,
     * so we will try to infer if its a directory if it looks like a directory
     * for the current operating system.
     */
 
    // if the last character passed is a path separator we assume is a directory
    if (looksLikeADirectory) {
        return getCacheFileForDirectory();
    }
 
    return resolvedCacheFile;
}
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
/**
 * Creates a new instance of the core CLI engine.
 * @param {CLIEngineOptions} options The options for this instance.
 * @constructor
 */
function CLIEngine(options) {
 
    options = Object.assign(
        Object.create(null),
        defaultOptions,
        { cwd: process.cwd() },
        options
    );
 
    /**
     * Stored options for this instance
     * @type {Object}
     */
    this.options = options;
 
    const cacheFile = getCacheFile(this.options.cacheLocation || this.options.cacheFile, this.options.cwd);
 
    /**
     * Cache used to avoid operating on files that haven't changed since the
     * last successful execution (e.g., file passed linting with no errors and
     * no warnings).
     * @type {Object}
     */
    this._fileCache = fileEntryCache.create(cacheFile);
 
    // load in additional rules
    if (this.options.rulePaths) {
        const cwd = this.options.cwd;
 
        this.options.rulePaths.forEach(rulesdir => {
            debug(`Loading rules from ${rulesdir}`);
            rules.load(rulesdir, cwd);
        });
    }
 
    Object.keys(this.options.rules || {}).forEach(name => {
        validator.validateRuleOptions(name, this.options.rules[name], "CLI");
    });
}
 
/**
 * Returns the formatter representing the given format or null if no formatter
 * with the given name can be found.
 * @param {string} [format] The name of the format to load or the path to a
 *      custom formatter.
 * @returns {Function} The formatter function or null if not found.
 */
CLIEngine.getFormatter = function(format) {
 
    let formatterPath;
 
    // default is stylish
    format = format || "stylish";
 
    // only strings are valid formatters
    if (typeof format === "string") {
 
        // replace \ with / for Windows compatibility
        format = format.replace(/\\/g, "/");
 
        // if there's a slash, then it's a file
        if (format.indexOf("/") > -1) {
            const cwd = this.options ? this.options.cwd : process.cwd();
 
            formatterPath = path.resolve(cwd, format);
        } else {
            formatterPath = `./formatters/${format}`;
        }
 
        try {
            return require(formatterPath);
        } catch (ex) {
            ex.message = `There was a problem loading formatter: ${formatterPath}\nError: ${ex.message}`;
            throw ex;
        }
 
    } else {
        return null;
    }
};
 
/**
 * Returns results that only contains errors.
 * @param {LintResult[]} results The results to filter.
 * @returns {LintResult[]} The filtered results.
 */
CLIEngine.getErrorResults = function(results) {
    const filtered = [];
 
    results.forEach(result => {
        const filteredMessages = result.messages.filter(isErrorMessage);
 
        if (filteredMessages.length > 0) {
            filtered.push(
                Object.assign(result, {
                    messages: filteredMessages,
                    errorCount: filteredMessages.length,
                    warningCount: 0
                })
            );
        }
    });
 
    return filtered;
};
 
/**
 * Outputs fixes from the given results to files.
 * @param {Object} report The report object created by CLIEngine.
 * @returns {void}
 */
CLIEngine.outputFixes = function(report) {
    report.results.filter(result => result.hasOwnProperty("output")).forEach(result => {
        fs.writeFileSync(result.filePath, result.output);
    });
};
 
CLIEngine.prototype = {
 
    constructor: CLIEngine,
 
    /**
     * Add a plugin by passing it's configuration
     * @param {string} name Name of the plugin.
     * @param {Object} pluginobject Plugin configuration object.
     * @returns {void}
     */
    addPlugin(name, pluginobject) {
        Plugins.define(name, pluginobject);
    },
 
    /**
     * Resolves the patterns passed into executeOnFiles() into glob-based patterns
     * for easier handling.
     * @param {string[]} patterns The file patterns passed on the command line.
     * @returns {string[]} The equivalent glob patterns.
     */
    resolveFileGlobPatterns(patterns) {
        return globUtil.resolveFileGlobPatterns(patterns, this.options);
    },
 
    /**
     * Executes the current configuration on an array of file and directory names.
     * @param {string[]} patterns An array of file and directory names.
     * @returns {Object} The results for all files that were linted.
     */
    executeOnFiles(patterns) {
        const results = [],
            options = this.options,
            fileCache = this._fileCache,
            configHelper = new Config(options);
        let prevConfig; // the previous configuration used
 
        /**
         * Calculates the hash of the config file used to validate a given file
         * @param  {string} filename The path of the file to retrieve a config object for to calculate the hash
         * @returns {string}         the hash of the config
         */
        function hashOfConfigFor(filename) {
            const config = configHelper.getConfig(filename);
 
            if (!prevConfig) {
                prevConfig = {};
            }
 
            // reuse the previously hashed config if the config hasn't changed
            if (prevConfig.config !== config) {
 
                /*
                 * config changed so we need to calculate the hash of the config
                 * and the hash of the plugins being used
                 */
                prevConfig.config = config;
 
                const eslintVersion = pkg.version;
 
                prevConfig.hash = hash(`${eslintVersion}_${stringify(config)}`);
            }
 
            return prevConfig.hash;
        }
 
        /**
         * Executes the linter on a file defined by the `filename`. Skips
         * unsupported file extensions and any files that are already linted.
         * @param {string} filename The resolved filename of the file to be linted
         * @param {boolean} warnIgnored always warn when a file is ignored
         * @returns {void}
         */
        function executeOnFile(filename, warnIgnored) {
            let hashOfConfig,
                descriptor;
 
            if (warnIgnored) {
                results.push(createIgnoreResult(filename, options.cwd));
                return;
            }
 
            if (options.cache) {
 
                /*
                 * get the descriptor for this file
                 * with the metadata and the flag that determines if
                 * the file has changed
                 */
                descriptor = fileCache.getFileDescriptor(filename);
                const meta = descriptor.meta || {};
 
                hashOfConfig = hashOfConfigFor(filename);
 
                const changed = descriptor.changed || meta.hashOfConfig !== hashOfConfig;
 
                if (!changed) {
                    debug(`Skipping file since hasn't changed: ${filename}`);
 
                    /*
                     * Add the the cached results (always will be 0 error and
                     * 0 warnings). We should not cache results for files that
                     * failed, in order to guarantee that next execution will
                     * process those files as well.
                     */
                    results.push(descriptor.meta.results);
 
                    // move to the next file
                    return;
                }
            } else {
                fileCache.destroy();
            }
 
            debug(`Processing ${filename}`);
 
            const res = processFile(filename, configHelper, options);
 
            if (options.cache) {
 
                /*
                 * if a file contains errors or warnings we don't want to
                 * store the file in the cache so we can guarantee that
                 * next execution will also operate on this file
                 */
                if (res.errorCount > 0 || res.warningCount > 0) {
                    debug(`File has problems, skipping it: ${filename}`);
 
                    // remove the entry from the cache
                    fileCache.removeEntry(filename);
                } else {
 
                    /*
                     * since the file passed we store the result here
                     * TODO: check this as we might not need to store the
                     * successful runs as it will always should be 0 errors and
                     * 0 warnings.
                     */
                    descriptor.meta.hashOfConfig = hashOfConfig;
                    descriptor.meta.results = res;
                }
            }
 
            results.push(res);
        }
 
        const startTime = Date.now();
 
 
 
        patterns = this.resolveFileGlobPatterns(patterns);
        const fileList = globUtil.listFilesToProcess(patterns, options);
 
        fileList.forEach(fileInfo => {
            executeOnFile(fileInfo.filename, fileInfo.ignored);
        });
 
        const stats = calculateStatsPerRun(results);
 
        if (options.cache) {
 
            // persist the cache to disk
            fileCache.reconcile();
        }
 
        debug(`Linting complete in: ${Date.now() - startTime}ms`);
 
        return {
            results,
            errorCount: stats.errorCount,
            warningCount: stats.warningCount
        };
    },
 
    /**
     * Executes the current configuration on text.
     * @param {string} text A string of JavaScript code to lint.
     * @param {string} filename An optional string representing the texts filename.
     * @param {boolean} warnIgnored Always warn when a file is ignored
     * @returns {Object} The results for the linting.
     */
    executeOnText(text, filename, warnIgnored) {
 
        const results = [],
            options = this.options,
            configHelper = new Config(options),
            ignoredPaths = new IgnoredPaths(options);
 
        // resolve filename based on options.cwd (for reporting, ignoredPaths also resolves)
        if (filename && !path.isAbsolute(filename)) {
            filename = path.resolve(options.cwd, filename);
        }
 
        if (filename && ignoredPaths.contains(filename)) {
            if (warnIgnored) {
                results.push(createIgnoreResult(filename, options.cwd));
            }
        } else {
            results.push(processText(text, configHelper, filename, options.fix, options.allowInlineConfig));
        }
 
        const stats = calculateStatsPerRun(results);
 
        return {
            results,
            errorCount: stats.errorCount,
            warningCount: stats.warningCount
        };
    },
 
    /**
     * Returns a configuration object for the given file based on the CLI options.
     * This is the same logic used by the ESLint CLI executable to determine
     * configuration for each file it processes.
     * @param {string} filePath The path of the file to retrieve a config object for.
     * @returns {Object} A configuration object for the file.
     */
    getConfigForFile(filePath) {
        const configHelper = new Config(this.options);
 
        return configHelper.getConfig(filePath);
    },
 
    /**
     * Checks if a given path is ignored by ESLint.
     * @param {string} filePath The path of the file to check.
     * @returns {boolean} Whether or not the given path is ignored.
     */
    isPathIgnored(filePath) {
        const resolvedPath = path.resolve(this.options.cwd, filePath);
        const ignoredPaths = new IgnoredPaths(this.options);
 
        return ignoredPaths.contains(resolvedPath);
    },
 
    getFormatter: CLIEngine.getFormatter
 
};
 
CLIEngine.version = pkg.version;
 
module.exports = CLIEngine;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/config.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/config.js

Statements: 7.89% (9 / 114)      Branches: 1.19% (1 / 84)      Functions: 0% (0 / 8)      Lines: 7.89% (9 / 114)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340                      1                 1           1                       1                   1                                                     1                                       1                   1                                                                                                                                                                                                                                                                                                                                                                                                                                                                               1    
/**
 * @fileoverview Responsible for loading config files
 * @author Seth McLaughlin
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const path = require("path"),
    ConfigOps = require("./config/config-ops"),
    ConfigFile = require("./config/config-file"),
    Plugins = require("./config/plugins"),
    FileFinder = require("./file-finder"),
    userHome = require("user-home"),
    isResolvable = require("is-resolvable"),
    pathIsInside = require("path-is-inside");
 
const debug = require("debug")("eslint:config");
 
//------------------------------------------------------------------------------
// Constants
//------------------------------------------------------------------------------
 
const PERSONAL_CONFIG_DIR = userHome || null;
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Check if item is an javascript object
 * @param {*} item object to check for
 * @returns {boolean} True if its an object
 * @private
 */
function isObject(item) {
    return typeof item === "object" && !Array.isArray(item) && item !== null;
}
 
/**
 * Load and parse a JSON config object from a file.
 * @param {string|Object} configToLoad the path to the JSON config file or the config object itself.
 * @returns {Object} the parsed config object (empty object if there was a parse error)
 * @private
 */
function loadConfig(configToLoad) {
    let config = {},
        filePath = "";
 
    if (configToLoad) {
 
        if (isObject(configToLoad)) {
            config = configToLoad;
 
            if (config.extends) {
                config = ConfigFile.applyExtends(config, filePath);
            }
        } else {
            filePath = configToLoad;
            config = ConfigFile.load(filePath);
        }
 
    }
 
    return config;
}
 
/**
 * Get personal config object from ~/.eslintrc.
 * @returns {Object} the personal config object (null if there is no personal config)
 * @private
 */
function getPersonalConfig() {
    let config;
 
    if (PERSONAL_CONFIG_DIR) {
        const filename = ConfigFile.getFilenameForDirectory(PERSONAL_CONFIG_DIR);
 
        if (filename) {
            debug("Using personal config");
            config = loadConfig(filename);
        }
    }
 
    return config || null;
}
 
/**
 * Determine if rules were explicitly passed in as options.
 * @param {Object} options The options used to create our configuration.
 * @returns {boolean} True if rules were passed in as options, false otherwise.
 */
function hasRules(options) {
    return options.rules && Object.keys(options.rules).length > 0;
}
 
/**
 * Get a local config object.
 * @param {Object} thisConfig A Config object.
 * @param {string} directory The directory to start looking in for a local config file.
 * @returns {Object} The local config object, or an empty object if there is no local config.
 */
function getLocalConfig(thisConfig, directory) {
    const localConfigFiles = thisConfig.findLocalConfigFiles(directory),
        numFiles = localConfigFiles.length,
        projectConfigPath = ConfigFile.getFilenameForDirectory(thisConfig.options.cwd);
    let found,
        config = {},
        rootPath;
 
    for (let i = 0; i < numFiles; i++) {
 
        const localConfigFile = localConfigFiles[i];
 
        // Don't consider the personal config file in the home directory,
        // except if the home directory is the same as the current working directory
        if (path.dirname(localConfigFile) === PERSONAL_CONFIG_DIR && localConfigFile !== projectConfigPath) {
            continue;
        }
 
        // If root flag is set, don't consider file if it is above root
        if (rootPath && !pathIsInside(path.dirname(localConfigFile), rootPath)) {
            continue;
        }
 
        debug(`Loading ${localConfigFile}`);
        const localConfig = loadConfig(localConfigFile);
 
        // Don't consider a local config file found if the config is null
        if (!localConfig) {
            continue;
        }
 
        // Check for root flag
        if (localConfig.root === true) {
            rootPath = path.dirname(localConfigFile);
        }
 
        found = true;
        debug(`Using ${localConfigFile}`);
        config = ConfigOps.merge(localConfig, config);
    }
 
    if (!found && !thisConfig.useSpecificConfig) {
 
        /*
         * - Is there a personal config in the user's home directory? If so,
         *   merge that with the passed-in config.
         * - Otherwise, if no rules were manually passed in, throw and error.
         * - Note: This function is not called if useEslintrc is false.
         */
        const personalConfig = getPersonalConfig();
 
        if (personalConfig) {
            config = ConfigOps.merge(config, personalConfig);
        } else if (!hasRules(thisConfig.options) && !thisConfig.options.baseConfig) {
 
            // No config file, no manual configuration, and no rules, so error.
            const noConfigError = new Error("No ESLint configuration found.");
 
            noConfigError.messageTemplate = "no-config-found";
            noConfigError.messageData = {
                directory,
                filesExamined: localConfigFiles
            };
 
            throw noConfigError;
        }
    }
 
    return config;
}
 
//------------------------------------------------------------------------------
// API
//------------------------------------------------------------------------------
 
/**
 * Configuration class
 */
class Config {
 
    /**
     * Config options
     * @param {Object} options Options to be passed in
     */
    constructor(options) {
        options = options || {};
 
        this.ignore = options.ignore;
        this.ignorePath = options.ignorePath;
        this.cache = {};
        this.parser = options.parser;
        this.parserOptions = options.parserOptions || {};
 
        this.baseConfig = options.baseConfig ? loadConfig(options.baseConfig) : { rules: {} };
 
        this.useEslintrc = (options.useEslintrc !== false);
 
        this.env = (options.envs || []).reduce((envs, name) => {
            envs[ name ] = true;
            return envs;
        }, {});
 
        /*
         * Handle declared globals.
         * For global variable foo, handle "foo:false" and "foo:true" to set
         * whether global is writable.
         * If user declares "foo", convert to "foo:false".
         */
        this.globals = (options.globals || []).reduce((globals, def) => {
            const parts = def.split(":");
 
            globals[parts[0]] = (parts.length > 1 && parts[1] === "true");
 
            return globals;
        }, {});
 
        const useConfig = options.configFile;
 
        this.options = options;
 
        if (useConfig) {
            debug(`Using command line config ${useConfig}`);
            if (isResolvable(useConfig) || isResolvable(`eslint-config-${useConfig}`) || useConfig.charAt(0) === "@") {
                this.useSpecificConfig = loadConfig(useConfig);
            } else {
                this.useSpecificConfig = loadConfig(path.resolve(this.options.cwd, useConfig));
            }
        }
    }
 
    /**
     * Build a config object merging the base config (conf/eslint-recommended),
     * the environments config (conf/environments.js) and eventually the user
     * config.
     * @param {string} filePath a file in whose directory we start looking for a local config
     * @returns {Object} config object
     */
    getConfig(filePath) {
        const directory = filePath ? path.dirname(filePath) : this.options.cwd;
        let config,
            userConfig;
 
        debug(`Constructing config for ${filePath ? filePath : "text"}`);
 
        config = this.cache[directory];
 
        if (config) {
            debug("Using config from cache");
            return config;
        }
 
        // Step 1: Determine user-specified config from .eslintrc.* and package.json files
        if (this.useEslintrc) {
            debug("Using .eslintrc and package.json files");
            userConfig = getLocalConfig(this, directory);
        } else {
            debug("Not using .eslintrc or package.json files");
            userConfig = {};
        }
 
        // Step 2: Create a copy of the baseConfig
        config = ConfigOps.merge({}, this.baseConfig);
 
        // Step 3: Merge in the user-specified configuration from .eslintrc and package.json
        config = ConfigOps.merge(config, userConfig);
 
        // Step 4: Merge in command line config file
        if (this.useSpecificConfig) {
            debug("Merging command line config file");
 
            config = ConfigOps.merge(config, this.useSpecificConfig);
        }
 
        // Step 5: Merge in command line environments
        debug("Merging command line environment settings");
        config = ConfigOps.merge(config, { env: this.env });
 
        // Step 6: Merge in command line rules
        if (this.options.rules) {
            debug("Merging command line rules");
            config = ConfigOps.merge(config, { rules: this.options.rules });
        }
 
        // Step 7: Merge in command line globals
        config = ConfigOps.merge(config, { globals: this.globals });
 
        // Only override parser if it is passed explicitly through the command line or if it's not
        // defined yet (because the final object will at least have the parser key)
        if (this.parser || !config.parser) {
            config = ConfigOps.merge(config, {
                parser: this.parser
            });
        }
 
        if (this.parserOptions) {
            config = ConfigOps.merge(config, {
                parserOptions: this.parserOptions
            });
        }
 
        // Step 8: Merge in command line plugins
        if (this.options.plugins) {
            debug("Merging command line plugins");
            Plugins.loadAll(this.options.plugins);
            config = ConfigOps.merge(config, { plugins: this.options.plugins });
        }
 
        // Step 9: Apply environments to the config if present
        if (config.env) {
            config = ConfigOps.applyEnvironments(config);
        }
 
        this.cache[directory] = config;
 
        return config;
    }
 
    /**
     * Find local config files from directory and parent directories.
     * @param {string} directory The directory to start searching from.
     * @returns {string[]} The paths of local config files found.
     */
    findLocalConfigFiles(directory) {
 
        if (!this.localConfigFinder) {
            this.localConfigFinder = new FileFinder(ConfigFile.CONFIG_FILES, this.options.cwd);
        }
 
        return this.localConfigFinder.findAllInDirectoryAndParents(directory);
    }
}
 
module.exports = Config;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/eslint.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/eslint.js

Statements: 10.86% (43 / 396)      Branches: 0% (0 / 233)      Functions: 2.78% (1 / 36)      Lines: 10.89% (43 / 395)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236                      1                                                                                         1                                                                   1                                                                                             1                                                 1                                                                                                                                                                                   1                                                     1                                                                                 1                                                                                                                                                                             1                                           1                                         1                                                                                                                             1             1                                       1                   1             1                                   1                                         1   1 1                                       1                                                                                                                                                 1                             1                 1           1                                                                     1                                                                                                                                                                                                                                                                                                                                                                                                                               1                                                                                                                                         1         1                                         1 17     17                       1               1                                                                                           1                                                             1                           1                 1                   1               1       1                                         1       1        
/**
 * @fileoverview Main ESLint object.
 * @author Nicholas C. Zakas
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const assert = require("assert"),
    EventEmitter = require("events").EventEmitter,
    escope = require("escope"),
    levn = require("levn"),
    blankScriptAST = require("../conf/blank-script.json"),
    DEFAULT_PARSER = require("../conf/eslint-recommended").parser,
    replacements = require("../conf/replacements.json"),
    CodePathAnalyzer = require("./code-path-analysis/code-path-analyzer"),
    ConfigOps = require("./config/config-ops"),
    validator = require("./config/config-validator"),
    Environments = require("./config/environments"),
    CommentEventGenerator = require("./util/comment-event-generator"),
    NodeEventGenerator = require("./util/node-event-generator"),
    SourceCode = require("./util/source-code"),
    Traverser = require("./util/traverser"),
    RuleContext = require("./rule-context"),
    rules = require("./rules"),
    timing = require("./timing"),
 
    pkg = require("../package.json");
 
 
//------------------------------------------------------------------------------
// Typedefs
//------------------------------------------------------------------------------
 
/**
 * The result of a parsing operation from parseForESLint()
 * @typedef {Object} CustomParseResult
 * @property {ASTNode} ast The ESTree AST Program node.
 * @property {Object} services An object containing additional services related
 *      to the parser.
 */
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Parses a list of "name:boolean_value" or/and "name" options divided by comma or
 * whitespace.
 * @param {string} string The string to parse.
 * @param {Comment} comment The comment node which has the string.
 * @returns {Object} Result map object of names and boolean values
 */
function parseBooleanConfig(string, comment) {
    const items = {};
 
    // Collapse whitespace around `:` and `,` to make parsing easier
    string = string.replace(/\s*([:,])\s*/g, "$1");
 
    string.split(/\s|,+/).forEach(name => {
        if (!name) {
            return;
        }
        const pos = name.indexOf(":");
        let value;
 
        if (pos !== -1) {
            value = name.substring(pos + 1, name.length);
            name = name.substring(0, pos);
        }
 
        items[name] = {
            value: (value === "true"),
            comment
        };
 
    });
    return items;
}
 
/**
 * Parses a JSON-like config.
 * @param {string} string The string to parse.
 * @param {Object} location Start line and column of comments for potential error message.
 * @param {Object[]} messages The messages queue for potential error message.
 * @returns {Object} Result map object
 */
function parseJsonConfig(string, location, messages) {
    let items = {};
 
    // Parses a JSON-like comment by the same way as parsing CLI option.
    try {
        items = levn.parse("Object", string) || {};
 
        // Some tests say that it should ignore invalid comments such as `/*eslint no-alert:abc*/`.
        // Also, commaless notations have invalid severity:
        //     "no-alert: 2 no-console: 2" --> {"no-alert": "2 no-console: 2"}
        // Should ignore that case as well.
        if (ConfigOps.isEverySeverityValid(items)) {
            return items;
        }
    } catch (ex) {
 
        // ignore to parse the string by a fallback.
    }
 
    // Optionator cannot parse commaless notations.
    // But we are supporting that. So this is a fallback for that.
    items = {};
    string = string.replace(/([a-zA-Z0-9\-/]+):/g, "\"$1\":").replace(/(]|[0-9])\s+(?=")/, "$1,");
    try {
        items = JSON.parse(`{${string}}`);
    } catch (ex) {
 
        messages.push({
            ruleId: null,
            fatal: true,
            severity: 2,
            source: null,
            message: `Failed to parse JSON from '${string}': ${ex.message}`,
            line: location.start.line,
            column: location.start.column + 1
        });
 
    }
 
    return items;
}
 
/**
 * Parses a config of values separated by comma.
 * @param {string} string The string to parse.
 * @returns {Object} Result map of values and true values
 */
function parseListConfig(string) {
    const items = {};
 
    // Collapse whitespace around ,
    string = string.replace(/\s*,\s*/g, ",");
 
    string.split(/,+/).forEach(name => {
        name = name.trim();
        if (!name) {
            return;
        }
        items[name] = true;
    });
    return items;
}
 
/**
 * Ensures that variables representing built-in properties of the Global Object,
 * and any globals declared by special block comments, are present in the global
 * scope.
 * @param {ASTNode} program The top node of the AST.
 * @param {Scope} globalScope The global scope.
 * @param {Object} config The existing configuration data.
 * @returns {void}
 */
function addDeclaredGlobals(program, globalScope, config) {
    const declaredGlobals = {},
        exportedGlobals = {},
        explicitGlobals = {},
        builtin = Environments.get("builtin");
 
    Object.assign(declaredGlobals, builtin);
 
    Object.keys(config.env).forEach(name => {
        if (config.env[name]) {
            const env = Environments.get(name),
                environmentGlobals = env && env.globals;
 
            if (environmentGlobals) {
                Object.assign(declaredGlobals, environmentGlobals);
            }
        }
    });
 
    Object.assign(exportedGlobals, config.exported);
    Object.assign(declaredGlobals, config.globals);
    Object.assign(explicitGlobals, config.astGlobals);
 
    Object.keys(declaredGlobals).forEach(name => {
        let variable = globalScope.set.get(name);
 
        if (!variable) {
            variable = new escope.Variable(name, globalScope);
            variable.eslintExplicitGlobal = false;
            globalScope.variables.push(variable);
            globalScope.set.set(name, variable);
        }
        variable.writeable = declaredGlobals[name];
    });
 
    Object.keys(explicitGlobals).forEach(name => {
        let variable = globalScope.set.get(name);
 
        if (!variable) {
            variable = new escope.Variable(name, globalScope);
            variable.eslintExplicitGlobal = true;
            variable.eslintExplicitGlobalComment = explicitGlobals[name].comment;
            globalScope.variables.push(variable);
            globalScope.set.set(name, variable);
        }
        variable.writeable = explicitGlobals[name].value;
    });
 
    // mark all exported variables as such
    Object.keys(exportedGlobals).forEach(name => {
        const variable = globalScope.set.get(name);
 
        if (variable) {
            variable.eslintUsed = true;
        }
    });
 
    /*
     * "through" contains all references which definitions cannot be found.
     * Since we augment the global scope using configuration, we need to update
     * references and remove the ones that were added by configuration.
     */
    globalScope.through = globalScope.through.filter(reference => {
        const name = reference.identifier.name;
        const variable = globalScope.set.get(name);
 
        if (variable) {
 
            /*
             * Links the variable and the reference.
             * And this reference is removed from `Scope#through`.
             */
            reference.resolved = variable;
            variable.references.push(reference);
 
            return false;
        }
 
        return true;
    });
}
 
/**
 * Add data to reporting configuration to disable reporting for list of rules
 * starting from start location
 * @param  {Object[]} reportingConfig Current reporting configuration
 * @param  {Object} start Position to start
 * @param  {string[]} rulesToDisable List of rules
 * @returns {void}
 */
function disableReporting(reportingConfig, start, rulesToDisable) {
 
    if (rulesToDisable.length) {
        rulesToDisable.forEach(rule => {
            reportingConfig.push({
                start,
                end: null,
                rule
            });
        });
    } else {
        reportingConfig.push({
            start,
            end: null,
            rule: null
        });
    }
}
 
/**
 * Add data to reporting configuration to enable reporting for list of rules
 * starting from start location
 * @param  {Object[]} reportingConfig Current reporting configuration
 * @param  {Object} start Position to start
 * @param  {string[]} rulesToEnable List of rules
 * @returns {void}
 */
function enableReporting(reportingConfig, start, rulesToEnable) {
    let i;
 
    if (rulesToEnable.length) {
        rulesToEnable.forEach(rule => {
            for (i = reportingConfig.length - 1; i >= 0; i--) {
                if (!reportingConfig[i].end && reportingConfig[i].rule === rule) {
                    reportingConfig[i].end = start;
                    break;
                }
            }
        });
    } else {
 
        // find all previous disabled locations if they was started as list of rules
        let prevStart;
 
        for (i = reportingConfig.length - 1; i >= 0; i--) {
            if (prevStart && prevStart !== reportingConfig[i].start) {
                break;
            }
 
            if (!reportingConfig[i].end) {
                reportingConfig[i].end = start;
                prevStart = reportingConfig[i].start;
            }
        }
    }
}
 
/**
 * Parses comments in file to extract file-specific config of rules, globals
 * and environments and merges them with global config; also code blocks
 * where reporting is disabled or enabled and merges them with reporting config.
 * @param {string} filename The file being checked.
 * @param {ASTNode} ast The top node of the AST.
 * @param {Object} config The existing configuration data.
 * @param {Object[]} reportingConfig The existing reporting configuration data.
 * @param {Object[]} messages The messages queue.
 * @returns {Object} Modified config object
 */
function modifyConfigsFromComments(filename, ast, config, reportingConfig, messages) {
 
    let commentConfig = {
        exported: {},
        astGlobals: {},
        rules: {},
        env: {}
    };
    const commentRules = {};
 
    ast.comments.forEach(comment => {
 
        let value = comment.value.trim();
        const match = /^(eslint(-\w+){0,3}|exported|globals?)(\s|$)/.exec(value);
 
        if (match) {
            value = value.substring(match.index + match[1].length);
 
            if (comment.type === "Block") {
                switch (match[1]) {
                    case "exported":
                        Object.assign(commentConfig.exported, parseBooleanConfig(value, comment));
                        break;
 
                    case "globals":
                    case "global":
                        Object.assign(commentConfig.astGlobals, parseBooleanConfig(value, comment));
                        break;
 
                    case "eslint-env":
                        Object.assign(commentConfig.env, parseListConfig(value));
                        break;
 
                    case "eslint-disable":
                        disableReporting(reportingConfig, comment.loc.start, Object.keys(parseListConfig(value)));
                        break;
 
                    case "eslint-enable":
                        enableReporting(reportingConfig, comment.loc.start, Object.keys(parseListConfig(value)));
                        break;
 
                    case "eslint": {
                        const items = parseJsonConfig(value, comment.loc, messages);
 
                        Object.keys(items).forEach(name => {
                            const ruleValue = items[name];
 
                            validator.validateRuleOptions(name, ruleValue, `${filename} line ${comment.loc.start.line}`);
                            commentRules[name] = ruleValue;
                        });
                        break;
                    }
 
                    // no default
                }
            } else {        // comment.type === "Line"
                if (match[1] === "eslint-disable-line") {
                    disableReporting(reportingConfig, { line: comment.loc.start.line, column: 0 }, Object.keys(parseListConfig(value)));
                    enableReporting(reportingConfig, comment.loc.end, Object.keys(parseListConfig(value)));
                } else if (match[1] === "eslint-disable-next-line") {
                    disableReporting(reportingConfig, comment.loc.start, Object.keys(parseListConfig(value)));
                    enableReporting(reportingConfig, { line: comment.loc.start.line + 2 }, Object.keys(parseListConfig(value)));
                }
            }
        }
    });
 
    // apply environment configs
    Object.keys(commentConfig.env).forEach(name => {
        const env = Environments.get(name);
 
        if (env) {
            commentConfig = ConfigOps.merge(commentConfig, env);
        }
    });
    Object.assign(commentConfig.rules, commentRules);
 
    return ConfigOps.merge(config, commentConfig);
}
 
/**
 * Check if message of rule with ruleId should be ignored in location
 * @param  {Object[]} reportingConfig  Collection of ignore records
 * @param  {string} ruleId   Id of rule
 * @param  {Object} location Location of message
 * @returns {boolean}          True if message should be ignored, false otherwise
 */
function isDisabledByReportingConfig(reportingConfig, ruleId, location) {
 
    for (let i = 0, c = reportingConfig.length; i < c; i++) {
 
        const ignore = reportingConfig[i];
 
        if ((!ignore.rule || ignore.rule === ruleId) &&
            (location.line > ignore.start.line || (location.line === ignore.start.line && location.column >= ignore.start.column)) &&
            (!ignore.end || (location.line < ignore.end.line || (location.line === ignore.end.line && location.column <= ignore.end.column)))) {
            return true;
        }
    }
 
    return false;
}
 
/**
 * Normalize ECMAScript version from the initial config
 * @param  {number} ecmaVersion ECMAScript version from the initial config
 * @param  {boolean} isModule Whether the source type is module or not
 * @returns {number} normalized ECMAScript version
 */
function normalizeEcmaVersion(ecmaVersion, isModule) {
 
    // Need at least ES6 for modules
    if (isModule && (!ecmaVersion || ecmaVersion < 6)) {
        ecmaVersion = 6;
    }
 
    // Calculate ECMAScript edition number from official year version starting with
    // ES2015, which corresponds with ES6 (or a difference of 2009).
    if (ecmaVersion >= 2015) {
        ecmaVersion -= 2009;
    }
 
    return ecmaVersion;
}
 
/**
 * Process initial config to make it safe to extend by file comment config
 * @param  {Object} config Initial config
 * @returns {Object}        Processed config
 */
function prepareConfig(config) {
 
    config.globals = config.globals || config.global || {};
    delete config.global;
 
    const copiedRules = {};
    let parserOptions = {};
 
    if (typeof config.rules === "object") {
        Object.keys(config.rules).forEach(k => {
            const rule = config.rules[k];
 
            if (rule === null) {
                throw new Error(`Invalid config for rule '${k}'.`);
            }
            if (Array.isArray(rule)) {
                copiedRules[k] = rule.slice();
            } else {
                copiedRules[k] = rule;
            }
        });
    }
 
    // merge in environment parserOptions
    if (typeof config.env === "object") {
        Object.keys(config.env).forEach(envName => {
            const env = Environments.get(envName);
 
            if (config.env[envName] && env && env.parserOptions) {
                parserOptions = ConfigOps.merge(parserOptions, env.parserOptions);
            }
        });
    }
 
    const preparedConfig = {
        rules: copiedRules,
        parser: config.parser || DEFAULT_PARSER,
        globals: ConfigOps.merge({}, config.globals),
        env: ConfigOps.merge({}, config.env || {}),
        settings: ConfigOps.merge({}, config.settings || {}),
        parserOptions: ConfigOps.merge(parserOptions, config.parserOptions || {})
    };
    const isModule = preparedConfig.parserOptions.sourceType === "module";
 
    if (isModule) {
        if (!preparedConfig.parserOptions.ecmaFeatures) {
            preparedConfig.parserOptions.ecmaFeatures = {};
        }
 
        // can't have global return inside of modules
        preparedConfig.parserOptions.ecmaFeatures.globalReturn = false;
    }
 
    preparedConfig.parserOptions.ecmaVersion = normalizeEcmaVersion(preparedConfig.parserOptions.ecmaVersion, isModule);
 
    return preparedConfig;
}
 
/**
 * Provide a stub rule with a given message
 * @param  {string} message The message to be displayed for the rule
 * @returns {Function}      Stub rule function
 */
function createStubRule(message) {
 
    /**
     * Creates a fake rule object
     * @param {Object} context context object for each rule
     * @returns {Object} collection of node to listen on
     */
    function createRuleModule(context) {
        return {
            Program(node) {
                context.report(node, message);
            }
        };
    }
 
    if (message) {
        return createRuleModule;
    }
    throw new Error("No message passed to stub rule");
 
}
 
/**
 * Provide a rule replacement message
 * @param  {string} ruleId Name of the rule
 * @returns {string}       Message detailing rule replacement
 */
function getRuleReplacementMessage(ruleId) {
    if (ruleId in replacements.rules) {
        const newRules = replacements.rules[ruleId];
 
        return `Rule '${ruleId}' was removed and replaced by: ${newRules.join(", ")}`;
    }
 
    return null;
}
 
const eslintEnvPattern = /\/\*\s*eslint-env\s(.+?)\*\//g;
 
/**
 * Checks whether or not there is a comment which has "eslint-env *" in a given text.
 * @param {string} text - A source code text to check.
 * @returns {Object|null} A result of parseListConfig() with "eslint-env *" comment.
 */
function findEslintEnv(text) {
    let match, retv;
 
    eslintEnvPattern.lastIndex = 0;
 
    while ((match = eslintEnvPattern.exec(text))) {
        retv = Object.assign(retv || {}, parseListConfig(match[1]));
    }
 
    return retv;
}
 
/**
 * Strips Unicode BOM from a given text.
 *
 * @param {string} text - A text to strip.
 * @returns {string} The stripped text.
 */
function stripUnicodeBOM(text) {
 
    /*
     * Check Unicode BOM.
     * In JavaScript, string data is stored as UTF-16, so BOM is 0xFEFF.
     * http://www.ecma-international.org/ecma-262/6.0/#sec-unicode-format-control-characters
     */
    if (text.charCodeAt(0) === 0xFEFF) {
        return text.slice(1);
    }
    return text;
}
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
/**
 * Object that is responsible for verifying JavaScript text
 * @name eslint
 */
module.exports = (function() {
 
    const api = Object.create(new EventEmitter());
    let messages = [],
        currentConfig = null,
        currentScopes = null,
        scopeManager = null,
        currentFilename = null,
        traverser = null,
        reportingConfig = [],
        sourceCode = null;
 
    /**
     * Parses text into an AST. Moved out here because the try-catch prevents
     * optimization of functions, so it's best to keep the try-catch as isolated
     * as possible
     * @param {string} text The text to parse.
     * @param {Object} config The ESLint configuration object.
     * @param {string} filePath The path to the file being parsed.
     * @returns {ASTNode|CustomParseResult} The AST or parse result if successful,
     *      or null if not.
     * @private
     */
    function parse(text, config, filePath) {
 
        let parser,
            parserOptions = {
                loc: true,
                range: true,
                raw: true,
                tokens: true,
                comment: true,
                attachComment: true,
                filePath
            };
 
        try {
            parser = require(config.parser);
        } catch (ex) {
            messages.push({
                ruleId: null,
                fatal: true,
                severity: 2,
                source: null,
                message: ex.message,
                line: 0,
                column: 0
            });
 
            return null;
        }
 
        // merge in any additional parser options
        if (config.parserOptions) {
            parserOptions = Object.assign({}, config.parserOptions, parserOptions);
        }
 
        /*
         * Check for parsing errors first. If there's a parsing error, nothing
         * else can happen. However, a parsing error does not throw an error
         * from this method - it's just considered a fatal error message, a
         * problem that ESLint identified just like any other.
         */
        try {
            if (typeof parser.parseForESLint === "function") {
                return parser.parseForESLint(text, parserOptions);
            }
            return parser.parse(text, parserOptions);
 
        } catch (ex) {
 
            // If the message includes a leading line number, strip it:
            const message = ex.message.replace(/^line \d+:/i, "").trim();
            const source = (ex.lineNumber) ? SourceCode.splitLines(text)[ex.lineNumber - 1] : null;
 
            messages.push({
                ruleId: null,
                fatal: true,
                severity: 2,
                source,
                message: `Parsing error: ${message}`,
 
                line: ex.lineNumber,
                column: ex.column
            });
 
            return null;
        }
    }
 
    /**
     * Get the severity level of a rule (0 - none, 1 - warning, 2 - error)
     * Returns 0 if the rule config is not valid (an Array or a number)
     * @param {Array|number} ruleConfig rule configuration
     * @returns {number} 0, 1, or 2, indicating rule severity
     */
    function getRuleSeverity(ruleConfig) {
        if (typeof ruleConfig === "number") {
            return ruleConfig;
        } else if (Array.isArray(ruleConfig)) {
            return ruleConfig[0];
        }
        return 0;
 
    }
 
    /**
     * Get the options for a rule (not including severity), if any
     * @param {Array|number} ruleConfig rule configuration
     * @returns {Array} of rule options, empty Array if none
     */
    function getRuleOptions(ruleConfig) {
        if (Array.isArray(ruleConfig)) {
            return ruleConfig.slice(1);
        }
        return [];
 
    }
 
    // set unlimited listeners (see https://github.com/eslint/eslint/issues/524)
    api.setMaxListeners(0);
 
    /**
     * Resets the internal state of the object.
     * @returns {void}
     */
    api.reset = function() {
        this.removeAllListeners();
        messages = [];
        currentConfig = null;
        currentScopes = null;
        scopeManager = null;
        traverser = null;
        reportingConfig = [];
        sourceCode = null;
    };
 
    /**
     * Configuration object for the `verify` API. A JS representation of the eslintrc files.
     * @typedef {Object} ESLintConfig
     * @property {Object} rules The rule configuration to verify against.
     * @property {string} [parser] Parser to use when generatig the AST.
     * @property {Object} [parserOptions] Options for the parsed used.
     * @property {Object} [settings] Global settings passed to each rule.
     * @property {Object} [env] The environment to verify in.
     * @property {Object} [globals] Available globalsto the code.
     */
 
    /**
     * Verifies the text against the rules specified by the second argument.
     * @param {string|SourceCode} textOrSourceCode The text to parse or a SourceCode object.
     * @param {ESLintConfig} config An ESLintConfig instance to configure everything.
     * @param {(string|Object)} [filenameOrOptions] The optional filename of the file being checked.
     *      If this is not set, the filename will default to '<input>' in the rule context. If
     *      an object, then it has "filename", "saveState", and "allowInlineConfig" properties.
     * @param {boolean} [saveState] Indicates if the state from the last run should be saved.
     *      Mostly useful for testing purposes.
     * @param {boolean} [filenameOrOptions.allowInlineConfig] Allow/disallow inline comments' ability to change config once it is set. Defaults to true if not supplied.
     *      Useful if you want to validate JS without comments overriding rules.
     * @returns {Object[]} The results as an array of messages or null if no messages.
     */
    api.verify = function(textOrSourceCode, config, filenameOrOptions, saveState) {
        const text = (typeof textOrSourceCode === "string") ? textOrSourceCode : null;
        let ast,
            parseResult,
            shebang,
            allowInlineConfig;
 
        // evaluate arguments
        if (typeof filenameOrOptions === "object") {
            currentFilename = filenameOrOptions.filename;
            allowInlineConfig = filenameOrOptions.allowInlineConfig;
            saveState = filenameOrOptions.saveState;
        } else {
            currentFilename = filenameOrOptions;
        }
 
        if (!saveState) {
            this.reset();
        }
 
        // search and apply "eslint-env *".
        const envInFile = findEslintEnv(text || textOrSourceCode.text);
 
        config = Object.assign({}, config);
 
        if (envInFile) {
            if (config.env) {
                config.env = Object.assign({}, config.env, envInFile);
            } else {
                config.env = envInFile;
            }
        }
 
        // process initial config to make it safe to extend
        config = prepareConfig(config);
 
        // only do this for text
        if (text !== null) {
 
            // there's no input, just exit here
            if (text.trim().length === 0) {
                sourceCode = new SourceCode(text, blankScriptAST);
                return messages;
            }
 
            parseResult = parse(
                stripUnicodeBOM(text).replace(/^#!([^\r\n]+)/, (match, captured) => {
                    shebang = captured;
                    return `//${captured}`;
                }),
                config,
                currentFilename
            );
 
            // if this result is from a parseForESLint() method, normalize
            if (parseResult && parseResult.ast) {
                ast = parseResult.ast;
            } else {
                ast = parseResult;
                parseResult = null;
            }
 
            if (ast) {
                sourceCode = new SourceCode(text, ast);
            }
 
        } else {
            sourceCode = textOrSourceCode;
            ast = sourceCode.ast;
        }
 
        // if espree failed to parse the file, there's no sense in setting up rules
        if (ast) {
 
            // parse global comments and modify config
            if (allowInlineConfig !== false) {
                config = modifyConfigsFromComments(currentFilename, ast, config, reportingConfig, messages);
            }
 
            // ensure that severities are normalized in the config
            ConfigOps.normalize(config);
 
            // enable appropriate rules
            Object.keys(config.rules).filter(key => getRuleSeverity(config.rules[key]) > 0).forEach(key => {
                let ruleCreator;
 
                ruleCreator = rules.get(key);
 
                if (!ruleCreator) {
                    const replacementMsg = getRuleReplacementMessage(key);
 
                    if (replacementMsg) {
                        ruleCreator = createStubRule(replacementMsg);
                    } else {
                        ruleCreator = createStubRule(`Definition for rule '${key}' was not found`);
                    }
                    rules.define(key, ruleCreator);
                }
 
                const severity = getRuleSeverity(config.rules[key]);
                const options = getRuleOptions(config.rules[key]);
 
                try {
                    const ruleContext = new RuleContext(
                        key, api, severity, options,
                        config.settings, config.parserOptions, config.parser,
                        ruleCreator.meta,
                        (parseResult && parseResult.services ? parseResult.services : {})
                    );
 
                    const rule = ruleCreator.create ? ruleCreator.create(ruleContext)
                        : ruleCreator(ruleContext);
 
                    // add all the selectors from the rule as listeners
                    Object.keys(rule).forEach(selector => {
                        api.on(selector, timing.enabled
                            ? timing.time(key, rule[selector])
                            : rule[selector]
                        );
                    });
                } catch (ex) {
                    ex.message = `Error while loading rule '${key}': ${ex.message}`;
                    throw ex;
                }
            });
 
            // save config so rules can access as necessary
            currentConfig = config;
            traverser = new Traverser();
 
            const ecmaFeatures = currentConfig.parserOptions.ecmaFeatures || {};
            const ecmaVersion = currentConfig.parserOptions.ecmaVersion || 5;
 
            // gather scope data that may be needed by the rules
            scopeManager = escope.analyze(ast, {
                ignoreEval: true,
                nodejsScope: ecmaFeatures.globalReturn,
                impliedStrict: ecmaFeatures.impliedStrict,
                ecmaVersion,
                sourceType: currentConfig.parserOptions.sourceType || "script",
                fallback: Traverser.getKeys
            });
 
            currentScopes = scopeManager.scopes;
 
            // augment global scope with declared global variables
            addDeclaredGlobals(ast, currentScopes[0], currentConfig);
 
            // remove shebang comments
            if (shebang && ast.comments.length && ast.comments[0].value === shebang) {
                ast.comments.splice(0, 1);
 
                if (ast.body.length && ast.body[0].leadingComments && ast.body[0].leadingComments[0].value === shebang) {
                    ast.body[0].leadingComments.splice(0, 1);
                }
            }
 
            let eventGenerator = new NodeEventGenerator(api);
 
            eventGenerator = new CodePathAnalyzer(eventGenerator);
            eventGenerator = new CommentEventGenerator(eventGenerator, sourceCode);
 
            /*
             * Each node has a type property. Whenever a particular type of
             * node is found, an event is fired. This allows any listeners to
             * automatically be informed that this type of node has been found
             * and react accordingly.
             */
            traverser.traverse(ast, {
                enter(node, parent) {
                    node.parent = parent;
                    eventGenerator.enterNode(node);
                },
                leave(node) {
                    eventGenerator.leaveNode(node);
                }
            });
        }
 
        // sort by line and column
        messages.sort((a, b) => {
            const lineDiff = a.line - b.line;
 
            if (lineDiff === 0) {
                return a.column - b.column;
            }
            return lineDiff;
 
        });
 
        return messages;
    };
 
    /**
     * Reports a message from one of the rules.
     * @param {string} ruleId The ID of the rule causing the message.
     * @param {number} severity The severity level of the rule as configured.
     * @param {ASTNode} node The AST node that the message relates to.
     * @param {Object=} location An object containing the error line and column
     *      numbers. If location is not provided the node's start location will
     *      be used.
     * @param {string} message The actual message.
     * @param {Object} opts Optional template data which produces a formatted message
     *     with symbols being replaced by this object's values.
     * @param {Object} fix A fix command description.
     * @param {Object} meta Metadata of the rule
     * @returns {void}
     */
    api.report = function(ruleId, severity, node, location, message, opts, fix, meta) {
        if (node) {
            assert.strictEqual(typeof node, "object", "Node must be an object");
        }
 
        if (typeof location === "string") {
            assert.ok(node, "Node must be provided when reporting error if location is not provided");
 
            meta = fix;
            fix = opts;
            opts = message;
            message = location;
            location = node.loc.start;
        }
 
        // Store end location.
        const endLocation = location.end;
 
        location = location.start || location;
 
        if (isDisabledByReportingConfig(reportingConfig, ruleId, location)) {
            return;
        }
 
        if (opts) {
            message = message.replace(/\{\{\s*([^{}]+?)\s*\}\}/g, (fullMatch, term) => {
                if (term in opts) {
                    return opts[term];
                }
 
                // Preserve old behavior: If parameter name not provided, don't replace it.
                return fullMatch;
            });
        }
 
        const problem = {
            ruleId,
            severity,
            message,
            line: location.line,
            column: location.column + 1,   // switch to 1-base instead of 0-base
            nodeType: node && node.type,
            source: sourceCode.lines[location.line - 1] || ""
        };
 
        // Define endLine and endColumn if exists.
        if (endLocation) {
            problem.endLine = endLocation.line;
            problem.endColumn = endLocation.column + 1;   // switch to 1-base instead of 0-base
        }
 
        // ensure there's range and text properties, otherwise it's not a valid fix
        if (fix && Array.isArray(fix.range) && (typeof fix.text === "string")) {
 
            // If rule uses fix, has metadata, but has no metadata.fixable, we should throw
            if (meta && !meta.fixable) {
                throw new Error("Fixable rules should export a `meta.fixable` property.");
            }
 
            problem.fix = fix;
        }
 
        messages.push(problem);
    };
 
    /**
     * Gets the SourceCode object representing the parsed source.
     * @returns {SourceCode} The SourceCode object.
     */
    api.getSourceCode = function() {
        return sourceCode;
    };
 
    // methods that exist on SourceCode object
    const externalMethods = {
        getSource: "getText",
        getSourceLines: "getLines",
        getAllComments: "getAllComments",
        getNodeByRangeIndex: "getNodeByRangeIndex",
        getComments: "getComments",
        getJSDocComment: "getJSDocComment",
        getFirstToken: "getFirstToken",
        getFirstTokens: "getFirstTokens",
        getLastToken: "getLastToken",
        getLastTokens: "getLastTokens",
        getTokenAfter: "getTokenAfter",
        getTokenBefore: "getTokenBefore",
        getTokenByRangeStart: "getTokenByRangeStart",
        getTokens: "getTokens",
        getTokensAfter: "getTokensAfter",
        getTokensBefore: "getTokensBefore",
        getTokensBetween: "getTokensBetween"
    };
 
    // copy over methods
    Object.keys(externalMethods).forEach(methodName => {
        const exMethodName = externalMethods[methodName];
 
        // All functions expected to have less arguments than 5.
        api[methodName] = function(a, b, c, d, e) {
            if (sourceCode) {
                return sourceCode[exMethodName](a, b, c, d, e);
            }
            return null;
        };
    });
 
    /**
     * Gets nodes that are ancestors of current node.
     * @returns {ASTNode[]} Array of objects representing ancestors.
     */
    api.getAncestors = function() {
        return traverser.parents();
    };
 
    /**
     * Gets the scope for the current node.
     * @returns {Object} An object representing the current node's scope.
     */
    api.getScope = function() {
        const parents = traverser.parents();
 
        // Don't do this for Program nodes - they have no parents
        if (parents.length) {
 
            // if current node introduces a scope, add it to the list
            const current = traverser.current();
 
            if (currentConfig.parserOptions.ecmaVersion >= 6) {
                if (["BlockStatement", "SwitchStatement", "CatchClause", "FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"].indexOf(current.type) >= 0) {
                    parents.push(current);
                }
            } else {
                if (["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"].indexOf(current.type) >= 0) {
                    parents.push(current);
                }
            }
 
            // Ascend the current node's parents
            for (let i = parents.length - 1; i >= 0; --i) {
 
                // Get the innermost scope
                const scope = scopeManager.acquire(parents[i], true);
 
                if (scope) {
                    if (scope.type === "function-expression-name") {
                        return scope.childScopes[0];
                    }
                    return scope;
 
                }
 
            }
 
        }
 
        return currentScopes[0];
    };
 
    /**
     * Record that a particular variable has been used in code
     * @param {string} name The name of the variable to mark as used
     * @returns {boolean} True if the variable was found and marked as used,
     *      false if not.
     */
    api.markVariableAsUsed = function(name) {
        const hasGlobalReturn = currentConfig.parserOptions.ecmaFeatures && currentConfig.parserOptions.ecmaFeatures.globalReturn,
            specialScope = hasGlobalReturn || currentConfig.parserOptions.sourceType === "module";
        let scope = this.getScope(),
            i,
            len;
 
        // Special Node.js scope means we need to start one level deeper
        if (scope.type === "global" && specialScope) {
            scope = scope.childScopes[0];
        }
 
        do {
            const variables = scope.variables;
 
            for (i = 0, len = variables.length; i < len; i++) {
                if (variables[i].name === name) {
                    variables[i].eslintUsed = true;
                    return true;
                }
            }
        } while ((scope = scope.upper));
 
        return false;
    };
 
    /**
     * Gets the filename for the currently parsed source.
     * @returns {string} The filename associated with the source being parsed.
     *     Defaults to "<input>" if no filename info is present.
     */
    api.getFilename = function() {
        if (typeof currentFilename === "string") {
            return currentFilename;
        }
        return "<input>";
 
    };
 
    /**
     * Defines a new linting rule.
     * @param {string} ruleId A unique rule identifier
     * @param {Function} ruleModule Function from context to object mapping AST node types to event handlers
     * @returns {void}
     */
    const defineRule = api.defineRule = function(ruleId, ruleModule) {
        rules.define(ruleId, ruleModule);
    };
 
    /**
     * Defines many new linting rules.
     * @param {Object} rulesToDefine map from unique rule identifier to rule
     * @returns {void}
     */
    api.defineRules = function(rulesToDefine) {
        Object.getOwnPropertyNames(rulesToDefine).forEach(ruleId => {
            defineRule(ruleId, rulesToDefine[ruleId]);
        });
    };
 
    /**
     * Gets the default eslint configuration.
     * @returns {Object} Object mapping rule IDs to their default configurations
     */
    api.defaults = function() {
        return require("../conf/eslint-recommended");
    };
 
    /**
     * Gets an object with all loaded rules.
     * @returns {Map} All loaded rules
     */
    api.getRules = function() {
        return rules.getAllLoadedRules();
    };
 
    api.version = pkg.version;
 
    /**
     * Gets variables that are declared by a specified node.
     *
     * The variables are its `defs[].node` or `defs[].parent` is same as the specified node.
     * Specifically, below:
     *
     * - `VariableDeclaration` - variables of its all declarators.
     * - `VariableDeclarator` - variables.
     * - `FunctionDeclaration`/`FunctionExpression` - its function name and parameters.
     * - `ArrowFunctionExpression` - its parameters.
     * - `ClassDeclaration`/`ClassExpression` - its class name.
     * - `CatchClause` - variables of its exception.
     * - `ImportDeclaration` - variables of  its all specifiers.
     * - `ImportSpecifier`/`ImportDefaultSpecifier`/`ImportNamespaceSpecifier` - a variable.
     * - others - always an empty array.
     *
     * @param {ASTNode} node A node to get.
     * @returns {escope.Variable[]} Variables that are declared by the node.
     */
    api.getDeclaredVariables = function(node) {
        return (scopeManager && scopeManager.getDeclaredVariables(node)) || [];
    };
 
    return api;
 
}());
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/file-finder.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/file-finder.js

Statements: 9.09% (4 / 44)      Branches: 0% (0 / 18)      Functions: 0% (0 / 4)      Lines: 9.09% (4 / 44)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143                      1                           1                             1                                                                                                                                                                                                       1    
/**
 * @fileoverview Util class to find config files.
 * @author Aliaksei Shytkin
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const fs = require("fs"),
    path = require("path");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Get the entries for a directory. Including a try-catch may be detrimental to
 * function performance, so move it out here a separate function.
 * @param {string} directory The directory to search in.
 * @returns {string[]} The entries in the directory or an empty array on error.
 * @private
 */
function getDirectoryEntries(directory) {
    try {
        return fs.readdirSync(directory);
    } catch (ex) {
        return [];
    }
}
 
/**
 * Create a hash of filenames from a directory listing
 * @param {string[]} entries Array of directory entries.
 * @param {string} directory Path to a current directory.
 * @param {string[]} supportedConfigs List of support filenames.
 * @returns {Object} Hashmap of filenames
 */
function normalizeDirectoryEntries(entries, directory, supportedConfigs) {
    const fileHash = {};
 
    entries.forEach(entry => {
        if (supportedConfigs.indexOf(entry) >= 0) {
            const resolvedEntry = path.resolve(directory, entry);
 
            if (fs.statSync(resolvedEntry).isFile()) {
                fileHash[entry] = resolvedEntry;
            }
        }
    });
    return fileHash;
}
 
//------------------------------------------------------------------------------
// API
//------------------------------------------------------------------------------
 
/**
 * FileFinder class
 */
class FileFinder {
 
    /**
     * @param {string[]} files The basename(s) of the file(s) to find.
     * @param {stirng} cwd Current working directory
     */
    constructor(files, cwd) {
        this.fileNames = Array.isArray(files) ? files : [files];
        this.cwd = cwd || process.cwd();
        this.cache = {};
    }
 
    /**
     * Find all instances of files with the specified file names, in directory and
     * parent directories. Cache the results.
     * Does not check if a matching directory entry is a file.
     * Searches for all the file names in this.fileNames.
     * Is currently used by lib/config.js to find .eslintrc and package.json files.
     * @param  {string} directory The directory to start the search from.
     * @returns {string[]} The file paths found.
     */
    findAllInDirectoryAndParents(directory) {
        const cache = this.cache;
 
        if (directory) {
            directory = path.resolve(this.cwd, directory);
        } else {
            directory = this.cwd;
        }
 
        if (cache.hasOwnProperty(directory)) {
            return cache[directory];
        }
 
        const dirs = [];
        const fileNames = this.fileNames;
        let searched = 0;
 
        do {
            dirs[searched++] = directory;
            cache[directory] = [];
 
            const filesMap = normalizeDirectoryEntries(getDirectoryEntries(directory), directory, fileNames);
 
            if (Object.keys(filesMap).length) {
                for (let k = 0; k < fileNames.length; k++) {
 
                    if (filesMap[fileNames[k]]) {
                        const filePath = filesMap[fileNames[k]];
 
                        // Add the file path to the cache of each directory searched.
                        for (let j = 0; j < searched; j++) {
                            cache[dirs[j]].push(filePath);
                        }
 
                        break;
                    }
                }
            }
            const child = directory;
 
            // Assign parent directory to directory.
            directory = path.dirname(directory);
 
            if (directory === child) {
                return cache[dirs[0]];
            }
        } while (!cache.hasOwnProperty(directory));
 
        // Add what has been cached previously to the cache of each directory searched.
        for (let i = 0; i < searched; i++) {
            dirs.push.apply(cache[dirs[i]], cache[directory]);
        }
 
        return cache[dirs[0]];
    }
}
 
module.exports = FileFinder;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/ignored-paths.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/ignored-paths.js

Statements: 13.89% (10 / 72)      Branches: 0% (0 / 36)      Functions: 0% (0 / 8)      Lines: 13.89% (10 / 72)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240                      1           1             1             1       1                               1                         1                                                   1                   1                                                                                                                                                                                                                                                                                 1    
/**
 * @fileoverview Responsible for loading ignore config files and managing ignore patterns
 * @author Jonathan Rajavuori
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const fs = require("fs"),
    path = require("path"),
    ignore = require("ignore"),
    shell = require("shelljs"),
    pathUtil = require("./util/path-util");
 
const debug = require("debug")("eslint:ignored-paths");
 
 
//------------------------------------------------------------------------------
// Constants
//------------------------------------------------------------------------------
 
const ESLINT_IGNORE_FILENAME = ".eslintignore";
 
/**
 * Adds `"*"` at the end of `"node_modules/"`,
 * so that subtle directories could be re-included by .gitignore patterns
 * such as `"!node_modules/should_not_ignored"`
 */
const DEFAULT_IGNORE_DIRS = [
    "/node_modules/*",
    "/bower_components/*"
];
const DEFAULT_OPTIONS = {
    dotfiles: false,
    cwd: process.cwd()
};
 
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
 
/**
 * Find an ignore file in the current directory.
 * @param {string} cwd Current working directory
 * @returns {string} Path of ignore file or an empty string.
 */
function findIgnoreFile(cwd) {
    cwd = cwd || DEFAULT_OPTIONS.cwd;
 
    const ignoreFilePath = path.resolve(cwd, ESLINT_IGNORE_FILENAME);
 
    return shell.test("-f", ignoreFilePath) ? ignoreFilePath : "";
}
 
/**
 * Merge options with defaults
 * @param {Object} options Options to merge with DEFAULT_OPTIONS constant
 * @returns {Object} Merged options
 */
function mergeDefaultOptions(options) {
    options = (options || {});
    return Object.assign({}, DEFAULT_OPTIONS, options);
}
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
/**
 * IgnoredPaths class
 */
class IgnoredPaths {
 
    /**
     * @param {Object} options object containing 'ignore', 'ignorePath' and 'patterns' properties
     */
    constructor(options) {
        options = mergeDefaultOptions(options);
 
        /**
         * add pattern to node-ignore instance
         * @param {Object} ig, instance of node-ignore
         * @param {string} pattern, pattern do add to ig
         * @returns {array} raw ignore rules
         */
        function addPattern(ig, pattern) {
            return ig.addPattern(pattern);
        }
 
        /**
         * add ignore file to node-ignore instance
         * @param {Object} ig, instance of node-ignore
         * @param {string} filepath, file to add to ig
         * @returns {array} raw ignore rules
         */
        function addIgnoreFile(ig, filepath) {
            ig.ignoreFiles.push(filepath);
            return ig.add(fs.readFileSync(filepath, "utf8"));
        }
 
        this.defaultPatterns = [].concat(DEFAULT_IGNORE_DIRS, options.patterns || []);
        this.baseDir = options.cwd;
 
        this.ig = {
            custom: ignore(),
            default: ignore()
        };
 
        // Add a way to keep track of ignored files.  This was present in node-ignore
        // 2.x, but dropped for now as of 3.0.10.
        this.ig.custom.ignoreFiles = [];
        this.ig.default.ignoreFiles = [];
 
        if (options.dotfiles !== true) {
 
            /*
             * ignore files beginning with a dot, but not files in a parent or
             * ancestor directory (which in relative format will begin with `../`).
             */
            addPattern(this.ig.default, [".*", "!../"]);
        }
 
        addPattern(this.ig.default, this.defaultPatterns);
 
        if (options.ignore !== false) {
            let ignorePath;
 
            if (options.ignorePath) {
                debug("Using specific ignore file");
 
                try {
                    fs.statSync(options.ignorePath);
                    ignorePath = options.ignorePath;
                } catch (e) {
                    e.message = `Cannot read ignore file: ${options.ignorePath}\nError: ${e.message}`;
                    throw e;
                }
            } else {
                debug(`Looking for ignore file in ${options.cwd}`);
                ignorePath = findIgnoreFile(options.cwd);
 
                try {
                    fs.statSync(ignorePath);
                    debug(`Loaded ignore file ${ignorePath}`);
                } catch (e) {
                    debug("Could not find ignore file in cwd");
                    this.options = options;
                }
            }
 
            if (ignorePath) {
                debug(`Adding ${ignorePath}`);
                this.baseDir = path.dirname(path.resolve(options.cwd, ignorePath));
                addIgnoreFile(this.ig.custom, ignorePath);
                addIgnoreFile(this.ig.default, ignorePath);
            }
 
            if (options.ignorePattern) {
                addPattern(this.ig.custom, options.ignorePattern);
                addPattern(this.ig.default, options.ignorePattern);
            }
        }
 
        this.options = options;
    }
 
    /**
     * Determine whether a file path is included in the default or custom ignore patterns
     * @param {string} filepath Path to check
     * @param {string} [category=null] check 'default', 'custom' or both (null)
     * @returns {boolean} true if the file path matches one or more patterns, false otherwise
     */
    contains(filepath, category) {
 
        let result = false;
        const absolutePath = path.resolve(this.options.cwd, filepath);
        const relativePath = pathUtil.getRelativePath(absolutePath, this.options.cwd);
 
        if ((typeof category === "undefined") || (category === "default")) {
            result = result || (this.ig.default.filter([relativePath]).length === 0);
        }
 
        if ((typeof category === "undefined") || (category === "custom")) {
            result = result || (this.ig.custom.filter([relativePath]).length === 0);
        }
 
        return result;
 
    }
 
    /**
     * Returns a list of dir patterns for glob to ignore
     * @returns {function()} method to check whether a folder should be ignored by glob.
     */
    getIgnoredFoldersGlobChecker() {
 
        const ig = ignore().add(DEFAULT_IGNORE_DIRS);
 
        if (this.options.dotfiles !== true) {
 
            // Ignore hidden folders.  (This cannot be ".*", or else it's not possible to unignore hidden files)
            ig.add([".*/*", "!../"]);
        }
 
        if (this.options.ignore) {
            ig.add(this.ig.custom);
        }
 
        const filter = ig.createFilter();
 
        /**
         * TODO
         * 1.
         * Actually, it should be `this.options.baseDir`, which is the base dir of `ignore-path`,
         * as well as Line 177.
         * But doing this leads to a breaking change and fails tests.
         * Related to #6759
         */
        const base = this.options.cwd;
 
        return function(absolutePath) {
            const relative = pathUtil.getRelativePath(absolutePath, base);
 
            if (!relative) {
                return false;
            }
 
            return !filter(relative);
        };
    }
}
 
module.exports = IgnoredPaths;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/load-rules.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/load-rules.js

Statements: 90.91% (10 / 11)      Branches: 75% (3 / 4)      Functions: 100% (1 / 1)      Lines: 90.91% (10 / 11)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43                      1                         1 2 2         2   2 490 2   488   2      
/**
 * @fileoverview Module for loading rules from files and directories.
 * @author Michael Ficarra
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const fs = require("fs"),
    path = require("path");
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
/**
 * Load all rule modules from specified directory.
 * @param {string} [rulesDir] Path to rules directory, may be relative. Defaults to `lib/rules`.
 * @param {string} cwd Current working directory
 * @returns {Object} Loaded rule modules by rule ids (file names).
 */
module.exports = function(rulesDir, cwd) {
    Eif (!rulesDir) {
        rulesDir = path.join(__dirname, "rules");
    } else {
        rulesDir = path.resolve(cwd, rulesDir);
    }
 
    const rules = Object.create(null);
 
    fs.readdirSync(rulesDir).forEach(file => {
        if (path.extname(file) !== ".js") {
            return;
        }
        rules[file.slice(0, -3)] = path.join(rulesDir, file);
    });
    return rules;
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/logging.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/logging.js

Statements: 100% (3 / 3)      Branches: 100% (0 / 0)      Functions: 100% (2 / 2)      Lines: 100% (3 / 3)      Ignored: 2 statements, 2 functions     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30                    1             1               1        
/**
 * @fileoverview Handle logging for ESLint
 * @author Gyandeep Singh
 */
 
"use strict";
 
/* eslint no-console: "off" */
 
/* istanbul ignore next */
module.exports = {
 
    /**
     * Cover for console.log
     * @returns {void}
     */
    info() {
        console.log.apply(console, Array.prototype.slice.call(arguments));
    },
 
    /**
     * Cover for console.error
     * @returns {void}
     */
    error() {
        console.error.apply(console, Array.prototype.slice.call(arguments));
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/options.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/options.js

Statements: 100% (2 / 2)      Branches: 100% (0 / 0)      Functions: 100% (0 / 0)      Lines: 100% (2 / 2)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225                      1             1                                                                                                                                                                                                                                                                                                                                                                                                                            
/**
 * @fileoverview Options configuration for optionator.
 * @author George Zahariev
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const optionator = require("optionator");
 
//------------------------------------------------------------------------------
// Initialization and Public Interface
//------------------------------------------------------------------------------
 
// exports "parse(args)", "generateHelp()", and "generateHelpForOption(optionName)"
module.exports = optionator({
    prepend: "eslint [options] file.js [file.js] [dir]",
    defaults: {
        concatRepeatedArrays: true,
        mergeRepeatedObjects: true
    },
    options: [
        {
            heading: "Basic configuration"
        },
        {
            option: "config",
            alias: "c",
            type: "path::String",
            description: "Use configuration from this file or shareable config"
        },
        {
            option: "eslintrc",
            type: "Boolean",
            default: "true",
            description: "Disable use of configuration from .eslintrc"
        },
        {
            option: "env",
            type: "[String]",
            description: "Specify environments"
        },
        {
            option: "ext",
            type: "[String]",
            default: ".js",
            description: "Specify JavaScript file extensions"
        },
        {
            option: "global",
            type: "[String]",
            description: "Define global variables"
        },
        {
            option: "parser",
            type: "String",
            description: "Specify the parser to be used"
        },
        {
            option: "parser-options",
            type: "Object",
            description: "Specify parser options"
        },
        {
            heading: "Caching"
        },
        {
            option: "cache",
            type: "Boolean",
            default: "false",
            description: "Only check changed files"
        },
        {
            option: "cache-file",
            type: "path::String",
            default: ".eslintcache",
            description: "Path to the cache file. Deprecated: use --cache-location"
        },
        {
            option: "cache-location",
            type: "path::String",
            description: "Path to the cache file or directory"
        },
        {
            heading: "Specifying rules and plugins"
        },
        {
            option: "rulesdir",
            type: "[path::String]",
            description: "Use additional rules from this directory"
        },
        {
            option: "plugin",
            type: "[String]",
            description: "Specify plugins"
        },
        {
            option: "rule",
            type: "Object",
            description: "Specify rules"
        },
        {
            heading: "Ignoring files"
        },
        {
            option: "ignore-path",
            type: "path::String",
            description: "Specify path of ignore file"
        },
        {
            option: "ignore",
            type: "Boolean",
            default: "true",
            description: "Disable use of ignore files and patterns"
        },
        {
            option: "ignore-pattern",
            type: "[String]",
            description: "Pattern of files to ignore (in addition to those in .eslintignore)",
            concatRepeatedArrays: [true, {
                oneValuePerFlag: true
            }]
        },
        {
            heading: "Using stdin"
        },
        {
            option: "stdin",
            type: "Boolean",
            default: "false",
            description: "Lint code provided on <STDIN>"
        },
        {
            option: "stdin-filename",
            type: "String",
            description: "Specify filename to process STDIN as"
        },
        {
            heading: "Handling warnings"
        },
        {
            option: "quiet",
            type: "Boolean",
            default: "false",
            description: "Report errors only"
        },
        {
            option: "max-warnings",
            type: "Int",
            default: "-1",
            description: "Number of warnings to trigger nonzero exit code"
        },
        {
            heading: "Output"
        },
        {
            option: "output-file",
            alias: "o",
            type: "path::String",
            description: "Specify file to write report to"
        },
        {
            option: "format",
            alias: "f",
            type: "String",
            default: "stylish",
            description: "Use a specific output format"
        },
        {
            option: "color",
            type: "Boolean",
            alias: "no-color",
            description: "Force enabling/disabling of color"
        },
        {
            heading: "Miscellaneous"
        },
        {
            option: "init",
            type: "Boolean",
            default: "false",
            description: "Run config initialization wizard"
        },
        {
            option: "fix",
            type: "Boolean",
            default: false,
            description: "Automatically fix problems"
        },
        {
            option: "debug",
            type: "Boolean",
            default: false,
            description: "Output debugging information"
        },
        {
            option: "help",
            alias: "h",
            type: "Boolean",
            description: "Show help"
        },
        {
            option: "version",
            alias: "v",
            type: "Boolean",
            description: "Output the version number"
        },
        {
            option: "inline-config",
            type: "Boolean",
            default: "true",
            description: "Prevent comments from changing config or rules"
        },
        {
            option: "print-config",
            type: "path::String",
            description: "Print the configuration for the given file"
        }
    ]
});
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rule-context.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rule-context.js

Statements: 20% (5 / 25)      Branches: 0% (0 / 6)      Functions: 20% (1 / 5)      Lines: 20% (5 / 25)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166                    1           1                                                                                                                                                                                                                                                                                         1 22         1    
/**
 * @fileoverview RuleContext utility for rules
 * @author Nicholas C. Zakas
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const ruleFixer = require("./util/rule-fixer");
 
//------------------------------------------------------------------------------
// Constants
//------------------------------------------------------------------------------
 
const PASSTHROUGHS = [
    "getAncestors",
    "getDeclaredVariables",
    "getFilename",
    "getScope",
    "markVariableAsUsed",
 
    // DEPRECATED
    "getAllComments",
    "getComments",
    "getFirstToken",
    "getFirstTokens",
    "getJSDocComment",
    "getLastToken",
    "getLastTokens",
    "getNodeByRangeIndex",
    "getSource",
    "getSourceLines",
    "getTokenAfter",
    "getTokenBefore",
    "getTokenByRangeStart",
    "getTokens",
    "getTokensAfter",
    "getTokensBefore",
    "getTokensBetween"
];
 
//------------------------------------------------------------------------------
// Typedefs
//------------------------------------------------------------------------------
 
/**
 * An error message description
 * @typedef {Object} MessageDescriptor
 * @property {string} nodeType The type of node.
 * @property {Location} loc The location of the problem.
 * @property {string} message The problem message.
 * @property {Object} [data] Optional data to use to fill in placeholders in the
 *      message.
 * @property {Function} fix The function to call that creates a fix command.
 */
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
/**
 * Rule context class
 * Acts as an abstraction layer between rules and the main eslint object.
 */
class RuleContext {
 
    /**
     * @param {string} ruleId The ID of the rule using this object.
     * @param {eslint} eslint The eslint object.
     * @param {number} severity The configured severity level of the rule.
     * @param {Array} options The configuration information to be added to the rule.
     * @param {Object} settings The configuration settings passed from the config file.
     * @param {Object} parserOptions The parserOptions settings passed from the config file.
     * @param {Object} parserPath The parser setting passed from the config file.
     * @param {Object} meta The metadata of the rule
     * @param {Object} parserServices The parser services for the rule.
     */
    constructor(ruleId, eslint, severity, options, settings, parserOptions, parserPath, meta, parserServices) {
 
        // public.
        this.id = ruleId;
        this.options = options;
        this.settings = settings;
        this.parserOptions = parserOptions;
        this.parserPath = parserPath;
        this.meta = meta;
 
        // create a separate copy and freeze it (it's not nice to freeze other people's objects)
        this.parserServices = Object.freeze(Object.assign({}, parserServices));
 
        // private.
        this.eslint = eslint;
        this.severity = severity;
 
        Object.freeze(this);
    }
 
    /**
     * Passthrough to eslint.getSourceCode().
     * @returns {SourceCode} The SourceCode object for the code.
     */
    getSourceCode() {
        return this.eslint.getSourceCode();
    }
 
    /**
     * Passthrough to eslint.report() that automatically assigns the rule ID and severity.
     * @param {ASTNode|MessageDescriptor} nodeOrDescriptor The AST node related to the message or a message
     *      descriptor.
     * @param {Object=} location The location of the error.
     * @param {string} message The message to display to the user.
     * @param {Object} opts Optional template data which produces a formatted message
     *     with symbols being replaced by this object's values.
     * @returns {void}
     */
    report(nodeOrDescriptor, location, message, opts) {
 
        // check to see if it's a new style call
        if (arguments.length === 1) {
            const descriptor = nodeOrDescriptor;
            let fix = null;
 
            // if there's a fix specified, get it
            if (typeof descriptor.fix === "function") {
                fix = descriptor.fix(ruleFixer);
            }
 
            this.eslint.report(
                this.id,
                this.severity,
                descriptor.node,
                descriptor.loc || descriptor.node.loc.start,
                descriptor.message,
                descriptor.data,
                fix,
                this.meta
            );
 
            return;
        }
 
        // old style call
        this.eslint.report(
            this.id,
            this.severity,
            nodeOrDescriptor,
            location,
            message,
            opts,
            this.meta
        );
    }
}
 
// Copy over passthrough methods. All functions will have 5 or fewer parameters.
PASSTHROUGHS.forEach(function(name) {
    this[name] = function(a, b, c, d, e) {
        return this.eslint[name](a, b, c, d, e);
    };
}, RuleContext.prototype);
 
module.exports = RuleContext;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules.js

Statements: 55.17% (16 / 29)      Branches: 25% (1 / 4)      Functions: 42.86% (3 / 7)      Lines: 55.17% (16 / 29)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127                      1           1                       1 244                 1 1   1 244                   1                               1 244 244                   1                               1       1                                             1    
/**
 * @fileoverview Defines a storage for rules.
 * @author Nicholas C. Zakas
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const loadRules = require("./load-rules");
 
//------------------------------------------------------------------------------
// Privates
//------------------------------------------------------------------------------
 
let rules = Object.create(null);
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
/**
 * Registers a rule module for rule id in storage.
 * @param {string} ruleId Rule id (file name).
 * @param {Function} ruleModule Rule handler.
 * @returns {void}
 */
function define(ruleId, ruleModule) {
    rules[ruleId] = ruleModule;
}
 
/**
 * Loads and registers all rules from passed rules directory.
 * @param {string} [rulesDir] Path to rules directory, may be relative. Defaults to `lib/rules`.
 * @param {string} cwd Current working directory
 * @returns {void}
 */
function load(rulesDir, cwd) {
    const newRules = loadRules(rulesDir, cwd);
 
    Object.keys(newRules).forEach(ruleId => {
        define(ruleId, newRules[ruleId]);
    });
}
 
/**
 * Registers all given rules of a plugin.
 * @param {Object} plugin The plugin object to import.
 * @param {string} pluginName The name of the plugin without prefix (`eslint-plugin-`).
 * @returns {void}
 */
function importPlugin(plugin, pluginName) {
    if (plugin.rules) {
        Object.keys(plugin.rules).forEach(ruleId => {
            const qualifiedRuleId = `${pluginName}/${ruleId}`,
                rule = plugin.rules[ruleId];
 
            define(qualifiedRuleId, rule);
        });
    }
}
 
/**
 * Access rule handler by id (file name).
 * @param {string} ruleId Rule id (file name).
 * @returns {Function} Rule handler.
 */
function getHandler(ruleId) {
    Eif (typeof rules[ruleId] === "string") {
        return require(rules[ruleId]);
    }
    return rules[ruleId];
 
}
 
/**
 * Get an object with all currently loaded rules
 * @returns {Map} All loaded rules
 */
function getAllLoadedRules() {
    const allRules = new Map();
 
    Object.keys(rules).forEach(name => {
        const rule = getHandler(name);
 
        allRules.set(name, rule);
    });
    return allRules;
}
 
/**
 * Reset rules storage.
 * Should be used only in tests.
 * @returns {void}
 */
function testClear() {
    rules = Object.create(null);
}
 
module.exports = {
    define,
    load,
    importPlugin,
    get: getHandler,
    getAllLoadedRules,
    testClear,
 
    /**
     * Resets rules to its starting state. Use for tests only.
     * @returns {void}
     */
    testReset() {
        testClear();
        load();
    }
};
 
//------------------------------------------------------------------------------
// Initialization
//------------------------------------------------------------------------------
 
// loads built-in rules
load();
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/timing.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/timing.js

Statements: 100% (47 / 47)      Branches: 100% (16 / 16)      Functions: 100% (6 / 6)      Lines: 100% (47 / 47)      Ignored: 36 statements, 5 functions, 15 branches     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143                                        1 1                       1 1             1   1 1                 1 1 1   1   1 1   1     1 1 1     1   1   1 1   1 1   1 1         1 1 1       1 1 1     1     1       1   1                 1 1 1     1 1   1 1 1       1 1 1       1              
/**
 * @fileoverview Tracks performance of individual rules.
 * @author Brandon Mills
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/* istanbul ignore next */
/**
 * Align the string to left
 * @param {string} str string to evaluate
 * @param {int} len length of the string
 * @param {string} ch delimiter character
 * @returns {string} modified string
 * @private
 */
function alignLeft(str, len, ch) {
    return str + new Array(len - str.length + 1).join(ch || " ");
}
 
/* istanbul ignore next */
/**
 * Align the string to right
 * @param {string} str string to evaluate
 * @param {int} len length of the string
 * @param {string} ch delimiter character
 * @returns {string} modified string
 * @private
 */
function alignRight(str, len, ch) {
    return new Array(len - str.length + 1).join(ch || " ") + str;
}
 
//------------------------------------------------------------------------------
// Module definition
//------------------------------------------------------------------------------
 
const enabled = !!process.env.TIMING;
 
const HEADERS = ["Rule", "Time (ms)", "Relative"];
const ALIGN = [alignLeft, alignRight, alignRight];
 
/* istanbul ignore next */
/**
 * display the data
 * @param {Object} data Data object to be displayed
 * @returns {string} modified string
 * @private
 */
function display(data) {
    let total = 0;
    const rows = Object.keys(data)
        .map(key => {
            const time = data[key];
 
            total += time;
            return [key, time];
        })
        .sort((a, b) => b[1] - a[1])
        .slice(0, 10);
 
    rows.forEach(row => {
        row.push(`${(row[1] * 100 / total).toFixed(1)}%`);
        row[1] = row[1].toFixed(3);
    });
 
    rows.unshift(HEADERS);
 
    const widths = [];
 
    rows.forEach(row => {
        const len = row.length;
 
        for (let i = 0; i < len; i++) {
            const n = row[i].length;
 
            if (!widths[i] || n > widths[i]) {
                widths[i] = n;
            }
        }
    });
 
    const table = rows.map(row =>
        row
            .map((cell, index) => ALIGN[index](cell, widths[index]))
            .join(" | ")
    );
 
    table.splice(1, 0, widths.map((w, index) => {
        if (index !== 0 && index !== widths.length - 1) {
            w++;
        }
 
        return ALIGN[index](":", w + 1, "-");
    }).join("|"));
 
    console.log(table.join("\n"));      // eslint-disable-line no-console
}
 
/* istanbul ignore next */
module.exports = (function() {
 
    const data = Object.create(null);
 
    /**
     * Time the run
     * @param {*} key key from the data object
     * @param {Function} fn function to be called
     * @returns {Function} function to be executed
     * @private
     */
    function time(key, fn) {
        if (typeof data[key] === "undefined") {
            data[key] = 0;
        }
 
        return function() {
            let t = process.hrtime();
 
            fn.apply(null, Array.prototype.slice.call(arguments));
            t = process.hrtime(t);
            data[key] += t[0] * 1e3 + t[1] / 1e6;
        };
    }
 
    Iif (enabled) {
        process.on("exit", () => {
            display(data);
        });
    }
 
    return {
        time,
        enabled
    };
 
}());
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/code-path-analysis/

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/code-path-analysis/

Statements: 9.52% (83 / 872)      Branches: 7.84% (33 / 421)      Functions: 2.86% (3 / 105)      Lines: 9.52% (83 / 872)      Ignored: 43 statements, 3 functions, 31 branches     

All files » node-npmtest-eslint/node_modules/eslint/lib/code-path-analysis/
File Statements Branches Functions Lines
code-path-analyzer.js 5.48% (12 / 219) 0% (0 / 161) 0% (0 / 14) 5.48% (12 / 219)
code-path-segment.js 12.24% (6 / 49) 8.33% (1 / 12) 0% (0 / 10) 12.24% (6 / 49)
code-path-state.js 3.86% (16 / 415) 3.11% (5 / 161) 0% (0 / 48) 3.86% (16 / 415)
code-path.js 6.25% (4 / 64) 0% (0 / 35) 0% (0 / 11) 6.25% (4 / 64)
debug-helpers.js 55.07% (38 / 69) 65% (26 / 40) 75% (3 / 4) 55.07% (38 / 69)
fork-context.js 10.2% (5 / 49) 0% (0 / 10) 0% (0 / 16) 10.2% (5 / 49)
id-generator.js 28.57% (2 / 7) 50% (1 / 2) 0% (0 / 2) 28.57% (2 / 7)
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/code-path-analysis/code-path-analyzer.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/code-path-analysis/code-path-analyzer.js

Statements: 5.48% (12 / 219)      Branches: 0% (0 / 161)      Functions: 0% (0 / 14)      Lines: 5.48% (12 / 219)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653                      1                                 1                     1                                                           1                             1                                                                                                       1                                                                                                               1                                                           1                                                                                                                                                                                                                     1                                                                                                                                                                                     1                                                                                                                                                                                                                       1                                                                                                                                                                                                                                                   1    
/**
 * @fileoverview A class of the code path analyzer.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const assert = require("assert"),
    CodePath = require("./code-path"),
    CodePathSegment = require("./code-path-segment"),
    IdGenerator = require("./id-generator"),
    debug = require("./debug-helpers"),
    astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks whether or not a given node is a `case` node (not `default` node).
 *
 * @param {ASTNode} node - A `SwitchCase` node to check.
 * @returns {boolean} `true` if the node is a `case` node (not `default` node).
 */
function isCaseNode(node) {
    return Boolean(node.test);
}
 
/**
 * Checks whether or not a given logical expression node goes different path
 * between the `true` case and the `false` case.
 *
 * @param {ASTNode} node - A node to check.
 * @returns {boolean} `true` if the node is a test of a choice statement.
 */
function isForkingByTrueOrFalse(node) {
    const parent = node.parent;
 
    switch (parent.type) {
        case "ConditionalExpression":
        case "IfStatement":
        case "WhileStatement":
        case "DoWhileStatement":
        case "ForStatement":
            return parent.test === node;
 
        case "LogicalExpression":
            return true;
 
        default:
            return false;
    }
}
 
/**
 * Gets the boolean value of a given literal node.
 *
 * This is used to detect infinity loops (e.g. `while (true) {}`).
 * Statements preceded by an infinity loop are unreachable if the loop didn't
 * have any `break` statement.
 *
 * @param {ASTNode} node - A node to get.
 * @returns {boolean|undefined} a boolean value if the node is a Literal node,
 *   otherwise `undefined`.
 */
function getBooleanValueIfSimpleConstant(node) {
    if (node.type === "Literal") {
        return Boolean(node.value);
    }
    return void 0;
}
 
/**
 * Checks that a given identifier node is a reference or not.
 *
 * This is used to detect the first throwable node in a `try` block.
 *
 * @param {ASTNode} node - An Identifier node to check.
 * @returns {boolean} `true` if the node is a reference.
 */
function isIdentifierReference(node) {
    const parent = node.parent;
 
    switch (parent.type) {
        case "LabeledStatement":
        case "BreakStatement":
        case "ContinueStatement":
        case "ArrayPattern":
        case "RestElement":
        case "ImportSpecifier":
        case "ImportDefaultSpecifier":
        case "ImportNamespaceSpecifier":
        case "CatchClause":
            return false;
 
        case "FunctionDeclaration":
        case "FunctionExpression":
        case "ArrowFunctionExpression":
        case "ClassDeclaration":
        case "ClassExpression":
        case "VariableDeclarator":
            return parent.id !== node;
 
        case "Property":
        case "MethodDefinition":
            return (
                parent.key !== node ||
                parent.computed ||
                parent.shorthand
            );
 
        case "AssignmentPattern":
            return parent.key !== node;
 
        default:
            return true;
    }
}
 
/**
 * Updates the current segment with the head segment.
 * This is similar to local branches and tracking branches of git.
 *
 * To separate the current and the head is in order to not make useless segments.
 *
 * In this process, both "onCodePathSegmentStart" and "onCodePathSegmentEnd"
 * events are fired.
 *
 * @param {CodePathAnalyzer} analyzer - The instance.
 * @param {ASTNode} node - The current AST node.
 * @returns {void}
 */
function forwardCurrentToHead(analyzer, node) {
    const codePath = analyzer.codePath;
    const state = CodePath.getState(codePath);
    const currentSegments = state.currentSegments;
    const headSegments = state.headSegments;
    const end = Math.max(currentSegments.length, headSegments.length);
    let i, currentSegment, headSegment;
 
    // Fires leaving events.
    for (i = 0; i < end; ++i) {
        currentSegment = currentSegments[i];
        headSegment = headSegments[i];
 
        if (currentSegment !== headSegment && currentSegment) {
            debug.dump(`onCodePathSegmentEnd ${currentSegment.id}`);
 
            if (currentSegment.reachable) {
                analyzer.emitter.emit(
                    "onCodePathSegmentEnd",
                    currentSegment,
                    node);
            }
        }
    }
 
    // Update state.
    state.currentSegments = headSegments;
 
    // Fires entering events.
    for (i = 0; i < end; ++i) {
        currentSegment = currentSegments[i];
        headSegment = headSegments[i];
 
        if (currentSegment !== headSegment && headSegment) {
            debug.dump(`onCodePathSegmentStart ${headSegment.id}`);
 
            CodePathSegment.markUsed(headSegment);
            if (headSegment.reachable) {
                analyzer.emitter.emit(
                    "onCodePathSegmentStart",
                    headSegment,
                    node);
            }
        }
    }
 
}
 
/**
 * Updates the current segment with empty.
 * This is called at the last of functions or the program.
 *
 * @param {CodePathAnalyzer} analyzer - The instance.
 * @param {ASTNode} node - The current AST node.
 * @returns {void}
 */
function leaveFromCurrentSegment(analyzer, node) {
    const state = CodePath.getState(analyzer.codePath);
    const currentSegments = state.currentSegments;
 
    for (let i = 0; i < currentSegments.length; ++i) {
        const currentSegment = currentSegments[i];
 
        debug.dump(`onCodePathSegmentEnd ${currentSegment.id}`);
        if (currentSegment.reachable) {
            analyzer.emitter.emit(
                "onCodePathSegmentEnd",
                currentSegment,
                node);
        }
    }
 
    state.currentSegments = [];
}
 
/**
 * Updates the code path due to the position of a given node in the parent node
 * thereof.
 *
 * For example, if the node is `parent.consequent`, this creates a fork from the
 * current path.
 *
 * @param {CodePathAnalyzer} analyzer - The instance.
 * @param {ASTNode} node - The current AST node.
 * @returns {void}
 */
function preprocess(analyzer, node) {
    const codePath = analyzer.codePath;
    const state = CodePath.getState(codePath);
    const parent = node.parent;
 
    switch (parent.type) {
        case "LogicalExpression":
            if (parent.right === node) {
                state.makeLogicalRight();
            }
            break;
 
        case "ConditionalExpression":
        case "IfStatement":
 
            /*
             * Fork if this node is at `consequent`/`alternate`.
             * `popForkContext()` exists at `IfStatement:exit` and
             * `ConditionalExpression:exit`.
             */
            if (parent.consequent === node) {
                state.makeIfConsequent();
            } else if (parent.alternate === node) {
                state.makeIfAlternate();
            }
            break;
 
        case "SwitchCase":
            if (parent.consequent[0] === node) {
                state.makeSwitchCaseBody(false, !parent.test);
            }
            break;
 
        case "TryStatement":
            if (parent.handler === node) {
                state.makeCatchBlock();
            } else if (parent.finalizer === node) {
                state.makeFinallyBlock();
            }
            break;
 
        case "WhileStatement":
            if (parent.test === node) {
                state.makeWhileTest(getBooleanValueIfSimpleConstant(node));
            } else {
                assert(parent.body === node);
                state.makeWhileBody();
            }
            break;
 
        case "DoWhileStatement":
            if (parent.body === node) {
                state.makeDoWhileBody();
            } else {
                assert(parent.test === node);
                state.makeDoWhileTest(getBooleanValueIfSimpleConstant(node));
            }
            break;
 
        case "ForStatement":
            if (parent.test === node) {
                state.makeForTest(getBooleanValueIfSimpleConstant(node));
            } else if (parent.update === node) {
                state.makeForUpdate();
            } else if (parent.body === node) {
                state.makeForBody();
            }
            break;
 
        case "ForInStatement":
        case "ForOfStatement":
            if (parent.left === node) {
                state.makeForInOfLeft();
            } else if (parent.right === node) {
                state.makeForInOfRight();
            } else {
                assert(parent.body === node);
                state.makeForInOfBody();
            }
            break;
 
        case "AssignmentPattern":
 
            /*
             * Fork if this node is at `right`.
             * `left` is executed always, so it uses the current path.
             * `popForkContext()` exists at `AssignmentPattern:exit`.
             */
            if (parent.right === node) {
                state.pushForkContext();
                state.forkBypassPath();
                state.forkPath();
            }
            break;
 
        default:
            break;
    }
}
 
/**
 * Updates the code path due to the type of a given node in entering.
 *
 * @param {CodePathAnalyzer} analyzer - The instance.
 * @param {ASTNode} node - The current AST node.
 * @returns {void}
 */
function processCodePathToEnter(analyzer, node) {
    let codePath = analyzer.codePath;
    let state = codePath && CodePath.getState(codePath);
    const parent = node.parent;
 
    switch (node.type) {
        case "Program":
        case "FunctionDeclaration":
        case "FunctionExpression":
        case "ArrowFunctionExpression":
            if (codePath) {
 
                // Emits onCodePathSegmentStart events if updated.
                forwardCurrentToHead(analyzer, node);
                debug.dumpState(node, state, false);
            }
 
            // Create the code path of this scope.
            codePath = analyzer.codePath = new CodePath(
                analyzer.idGenerator.next(),
                codePath,
                analyzer.onLooped
            );
            state = CodePath.getState(codePath);
 
            // Emits onCodePathStart events.
            debug.dump(`onCodePathStart ${codePath.id}`);
            analyzer.emitter.emit("onCodePathStart", codePath, node);
            break;
 
        case "LogicalExpression":
            state.pushChoiceContext(node.operator, isForkingByTrueOrFalse(node));
            break;
 
        case "ConditionalExpression":
        case "IfStatement":
            state.pushChoiceContext("test", false);
            break;
 
        case "SwitchStatement":
            state.pushSwitchContext(
                node.cases.some(isCaseNode),
                astUtils.getLabel(node));
            break;
 
        case "TryStatement":
            state.pushTryContext(Boolean(node.finalizer));
            break;
 
        case "SwitchCase":
 
            /*
             * Fork if this node is after the 2st node in `cases`.
             * It's similar to `else` blocks.
             * The next `test` node is processed in this path.
             */
            if (parent.discriminant !== node && parent.cases[0] !== node) {
                state.forkPath();
            }
            break;
 
        case "WhileStatement":
        case "DoWhileStatement":
        case "ForStatement":
        case "ForInStatement":
        case "ForOfStatement":
            state.pushLoopContext(node.type, astUtils.getLabel(node));
            break;
 
        case "LabeledStatement":
            if (!astUtils.isBreakableStatement(node.body)) {
                state.pushBreakContext(false, node.label.name);
            }
            break;
 
        default:
            break;
    }
 
    // Emits onCodePathSegmentStart events if updated.
    forwardCurrentToHead(analyzer, node);
    debug.dumpState(node, state, false);
}
 
/**
 * Updates the code path due to the type of a given node in leaving.
 *
 * @param {CodePathAnalyzer} analyzer - The instance.
 * @param {ASTNode} node - The current AST node.
 * @returns {void}
 */
function processCodePathToExit(analyzer, node) {
    const codePath = analyzer.codePath;
    const state = CodePath.getState(codePath);
    let dontForward = false;
 
    switch (node.type) {
        case "IfStatement":
        case "ConditionalExpression":
        case "LogicalExpression":
            state.popChoiceContext();
            break;
 
        case "SwitchStatement":
            state.popSwitchContext();
            break;
 
        case "SwitchCase":
 
            /*
             * This is the same as the process at the 1st `consequent` node in
             * `preprocess` function.
             * Must do if this `consequent` is empty.
             */
            if (node.consequent.length === 0) {
                state.makeSwitchCaseBody(true, !node.test);
            }
            if (state.forkContext.reachable) {
                dontForward = true;
            }
            break;
 
        case "TryStatement":
            state.popTryContext();
            break;
 
        case "BreakStatement":
            forwardCurrentToHead(analyzer, node);
            state.makeBreak(node.label && node.label.name);
            dontForward = true;
            break;
 
        case "ContinueStatement":
            forwardCurrentToHead(analyzer, node);
            state.makeContinue(node.label && node.label.name);
            dontForward = true;
            break;
 
        case "ReturnStatement":
            forwardCurrentToHead(analyzer, node);
            state.makeReturn();
            dontForward = true;
            break;
 
        case "ThrowStatement":
            forwardCurrentToHead(analyzer, node);
            state.makeThrow();
            dontForward = true;
            break;
 
        case "Identifier":
            if (isIdentifierReference(node)) {
                state.makeFirstThrowablePathInTryBlock();
                dontForward = true;
            }
            break;
 
        case "CallExpression":
        case "MemberExpression":
        case "NewExpression":
            state.makeFirstThrowablePathInTryBlock();
            break;
 
        case "WhileStatement":
        case "DoWhileStatement":
        case "ForStatement":
        case "ForInStatement":
        case "ForOfStatement":
            state.popLoopContext();
            break;
 
        case "AssignmentPattern":
            state.popForkContext();
            break;
 
        case "LabeledStatement":
            if (!astUtils.isBreakableStatement(node.body)) {
                state.popBreakContext();
            }
            break;
 
        default:
            break;
    }
 
    // Emits onCodePathSegmentStart events if updated.
    if (!dontForward) {
        forwardCurrentToHead(analyzer, node);
    }
    debug.dumpState(node, state, true);
}
 
/**
 * Updates the code path to finalize the current code path.
 *
 * @param {CodePathAnalyzer} analyzer - The instance.
 * @param {ASTNode} node - The current AST node.
 * @returns {void}
 */
function postprocess(analyzer, node) {
    switch (node.type) {
        case "Program":
        case "FunctionDeclaration":
        case "FunctionExpression":
        case "ArrowFunctionExpression": {
            let codePath = analyzer.codePath;
 
            // Mark the current path as the final node.
            CodePath.getState(codePath).makeFinal();
 
            // Emits onCodePathSegmentEnd event of the current segments.
            leaveFromCurrentSegment(analyzer, node);
 
            // Emits onCodePathEnd event of this code path.
            debug.dump(`onCodePathEnd ${codePath.id}`);
            analyzer.emitter.emit("onCodePathEnd", codePath, node);
            debug.dumpDot(codePath);
 
            codePath = analyzer.codePath = analyzer.codePath.upper;
            if (codePath) {
                debug.dumpState(node, CodePath.getState(codePath), true);
            }
            break;
        }
 
        default:
            break;
    }
}
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
/**
 * The class to analyze code paths.
 * This class implements the EventGenerator interface.
 */
class CodePathAnalyzer {
 
    /**
     * @param {EventGenerator} eventGenerator - An event generator to wrap.
     */
    constructor(eventGenerator) {
        this.original = eventGenerator;
        this.emitter = eventGenerator.emitter;
        this.codePath = null;
        this.idGenerator = new IdGenerator("s");
        this.currentNode = null;
        this.onLooped = this.onLooped.bind(this);
    }
 
    /**
     * Does the process to enter a given AST node.
     * This updates state of analysis and calls `enterNode` of the wrapped.
     *
     * @param {ASTNode} node - A node which is entering.
     * @returns {void}
     */
    enterNode(node) {
        this.currentNode = node;
 
        // Updates the code path due to node's position in its parent node.
        if (node.parent) {
            preprocess(this, node);
        }
 
        // Updates the code path.
        // And emits onCodePathStart/onCodePathSegmentStart events.
        processCodePathToEnter(this, node);
 
        // Emits node events.
        this.original.enterNode(node);
 
        this.currentNode = null;
    }
 
    /**
     * Does the process to leave a given AST node.
     * This updates state of analysis and calls `leaveNode` of the wrapped.
     *
     * @param {ASTNode} node - A node which is leaving.
     * @returns {void}
     */
    leaveNode(node) {
        this.currentNode = node;
 
        // Updates the code path.
        // And emits onCodePathStart/onCodePathSegmentStart events.
        processCodePathToExit(this, node);
 
        // Emits node events.
        this.original.leaveNode(node);
 
        // Emits the last onCodePathStart/onCodePathSegmentStart events.
        postprocess(this, node);
 
        this.currentNode = null;
    }
 
    /**
     * This is called on a code path looped.
     * Then this raises a looped event.
     *
     * @param {CodePathSegment} fromSegment - A segment of prev.
     * @param {CodePathSegment} toSegment - A segment of next.
     * @returns {void}
     */
    onLooped(fromSegment, toSegment) {
        if (fromSegment.reachable && toSegment.reachable) {
            debug.dump(`onCodePathSegmentLoop ${fromSegment.id} -> ${toSegment.id}`);
            this.emitter.emit(
                "onCodePathSegmentLoop",
                fromSegment,
                toSegment,
                this.currentNode
            );
        }
    }
}
 
module.exports = CodePathAnalyzer;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/code-path-analysis/code-path-segment.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/code-path-analysis/code-path-segment.js

Statements: 12.24% (6 / 49)      Branches: 8.33% (1 / 12)      Functions: 0% (0 / 10)      Lines: 12.24% (6 / 49)      Ignored: 2 statements, 1 branch     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244                      1                       1                                                                         1                                                                                                                                           1 1                                                                                                                                                                                                                           1    
/**
 * @fileoverview A class of the code path segment.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const debug = require("./debug-helpers");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Replaces unused segments with the previous segments of each unused segment.
 *
 * @param {CodePathSegment[]} segments - An array of segments to replace.
 * @returns {CodePathSegment[]} The replaced array.
 */
function flattenUnusedSegments(segments) {
    const done = Object.create(null);
    const retv = [];
 
    for (let i = 0; i < segments.length; ++i) {
        const segment = segments[i];
 
        // Ignores duplicated.
        if (done[segment.id]) {
            continue;
        }
 
        // Use previous segments if unused.
        if (!segment.internal.used) {
            for (let j = 0; j < segment.allPrevSegments.length; ++j) {
                const prevSegment = segment.allPrevSegments[j];
 
                if (!done[prevSegment.id]) {
                    done[prevSegment.id] = true;
                    retv.push(prevSegment);
                }
            }
        } else {
            done[segment.id] = true;
            retv.push(segment);
        }
    }
 
    return retv;
}
 
/**
 * Checks whether or not a given segment is reachable.
 *
 * @param {CodePathSegment} segment - A segment to check.
 * @returns {boolean} `true` if the segment is reachable.
 */
function isReachable(segment) {
    return segment.reachable;
}
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
/**
 * A code path segment.
 */
class CodePathSegment {
 
    /**
     * @param {string} id - An identifier.
     * @param {CodePathSegment[]} allPrevSegments - An array of the previous segments.
     *   This array includes unreachable segments.
     * @param {boolean} reachable - A flag which shows this is reachable.
     */
    constructor(id, allPrevSegments, reachable) {
 
        /**
         * The identifier of this code path.
         * Rules use it to store additional information of each rule.
         * @type {string}
         */
        this.id = id;
 
        /**
         * An array of the next segments.
         * @type {CodePathSegment[]}
         */
        this.nextSegments = [];
 
        /**
         * An array of the previous segments.
         * @type {CodePathSegment[]}
         */
        this.prevSegments = allPrevSegments.filter(isReachable);
 
        /**
         * An array of the next segments.
         * This array includes unreachable segments.
         * @type {CodePathSegment[]}
         */
        this.allNextSegments = [];
 
        /**
         * An array of the previous segments.
         * This array includes unreachable segments.
         * @type {CodePathSegment[]}
         */
        this.allPrevSegments = allPrevSegments;
 
        /**
         * A flag which shows this is reachable.
         * @type {boolean}
         */
        this.reachable = reachable;
 
        // Internal data.
        Object.defineProperty(this, "internal", {
            value: {
                used: false,
                loopedPrevSegments: []
            }
        });
 
        /* istanbul ignore if */
        if (debug.enabled) {
            this.internal.nodes = [];
            this.internal.exitNodes = [];
        }
    }
 
    /**
     * Checks a given previous segment is coming from the end of a loop.
     *
     * @param {CodePathSegment} segment - A previous segment to check.
     * @returns {boolean} `true` if the segment is coming from the end of a loop.
     */
    isLoopedPrevSegment(segment) {
        return this.internal.loopedPrevSegments.indexOf(segment) !== -1;
    }
 
    /**
     * Creates the root segment.
     *
     * @param {string} id - An identifier.
     * @returns {CodePathSegment} The created segment.
     */
    static newRoot(id) {
        return new CodePathSegment(id, [], true);
    }
 
    /**
     * Creates a segment that follows given segments.
     *
     * @param {string} id - An identifier.
     * @param {CodePathSegment[]} allPrevSegments - An array of the previous segments.
     * @returns {CodePathSegment} The created segment.
     */
    static newNext(id, allPrevSegments) {
        return new CodePathSegment(
            id,
            flattenUnusedSegments(allPrevSegments),
            allPrevSegments.some(isReachable));
    }
 
    /**
     * Creates an unreachable segment that follows given segments.
     *
     * @param {string} id - An identifier.
     * @param {CodePathSegment[]} allPrevSegments - An array of the previous segments.
     * @returns {CodePathSegment} The created segment.
     */
    static newUnreachable(id, allPrevSegments) {
        const segment = new CodePathSegment(id, flattenUnusedSegments(allPrevSegments), false);
 
        // In `if (a) return a; foo();` case, the unreachable segment preceded by
        // the return statement is not used but must not be remove.
        CodePathSegment.markUsed(segment);
 
        return segment;
    }
 
    /**
     * Creates a segment that follows given segments.
     * This factory method does not connect with `allPrevSegments`.
     * But this inherits `reachable` flag.
     *
     * @param {string} id - An identifier.
     * @param {CodePathSegment[]} allPrevSegments - An array of the previous segments.
     * @returns {CodePathSegment} The created segment.
     */
    static newDisconnected(id, allPrevSegments) {
        return new CodePathSegment(id, [], allPrevSegments.some(isReachable));
    }
 
    /**
     * Makes a given segment being used.
     *
     * And this function registers the segment into the previous segments as a next.
     *
     * @param {CodePathSegment} segment - A segment to mark.
     * @returns {void}
     */
    static markUsed(segment) {
        if (segment.internal.used) {
            return;
        }
        segment.internal.used = true;
 
        let i;
 
        if (segment.reachable) {
            for (i = 0; i < segment.allPrevSegments.length; ++i) {
                const prevSegment = segment.allPrevSegments[i];
 
                prevSegment.allNextSegments.push(segment);
                prevSegment.nextSegments.push(segment);
            }
        } else {
            for (i = 0; i < segment.allPrevSegments.length; ++i) {
                segment.allPrevSegments[i].allNextSegments.push(segment);
            }
        }
    }
 
    /**
     * Marks a previous segment as looped.
     *
     * @param {CodePathSegment} segment - A segment.
     * @param {CodePathSegment} prevSegment - A previous segment to mark.
     * @returns {void}
     */
    static markPrevSegmentAsLooped(segment, prevSegment) {
        segment.internal.loopedPrevSegments.push(prevSegment);
    }
}
 
module.exports = CodePathSegment;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/code-path-analysis/code-path-state.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/code-path-analysis/code-path-state.js

Statements: 3.86% (16 / 415)      Branches: 3.11% (5 / 161)      Functions: 0% (0 / 48)      Lines: 3.86% (16 / 415)      Ignored: 5 statements, 5 branches     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430                      1                                       1                                   1                             1                   1                     1                 1                                     1                                           1                             1                                       1                                                                     1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               1                                                                                                                             1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       1    
/**
 * @fileoverview A class to manage state of generating a code path.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const CodePathSegment = require("./code-path-segment"),
    ForkContext = require("./fork-context");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Adds given segments into the `dest` array.
 * If the `others` array does not includes the given segments, adds to the `all`
 * array as well.
 *
 * This adds only reachable and used segments.
 *
 * @param {CodePathSegment[]} dest - A destination array (`returnedSegments` or `thrownSegments`).
 * @param {CodePathSegment[]} others - Another destination array (`returnedSegments` or `thrownSegments`).
 * @param {CodePathSegment[]} all - The unified destination array (`finalSegments`).
 * @param {CodePathSegment[]} segments - Segments to add.
 * @returns {void}
 */
function addToReturnedOrThrown(dest, others, all, segments) {
    for (let i = 0; i < segments.length; ++i) {
        const segment = segments[i];
 
        dest.push(segment);
        if (others.indexOf(segment) === -1) {
            all.push(segment);
        }
    }
}
 
/**
 * Gets a loop-context for a `continue` statement.
 *
 * @param {CodePathState} state - A state to get.
 * @param {string} label - The label of a `continue` statement.
 * @returns {LoopContext} A loop-context for a `continue` statement.
 */
function getContinueContext(state, label) {
    if (!label) {
        return state.loopContext;
    }
 
    let context = state.loopContext;
 
    while (context) {
        if (context.label === label) {
            return context;
        }
        context = context.upper;
    }
 
    /* istanbul ignore next: foolproof (syntax error) */
    return null;
}
 
/**
 * Gets a context for a `break` statement.
 *
 * @param {CodePathState} state - A state to get.
 * @param {string} label - The label of a `break` statement.
 * @returns {LoopContext|SwitchContext} A context for a `break` statement.
 */
function getBreakContext(state, label) {
    let context = state.breakContext;
 
    while (context) {
        if (label ? context.label === label : context.breakable) {
            return context;
        }
        context = context.upper;
    }
 
    /* istanbul ignore next: foolproof (syntax error) */
    return null;
}
 
/**
 * Gets a context for a `return` statement.
 *
 * @param {CodePathState} state - A state to get.
 * @returns {TryContext|CodePathState} A context for a `return` statement.
 */
function getReturnContext(state) {
    let context = state.tryContext;
 
    while (context) {
        if (context.hasFinalizer && context.position !== "finally") {
            return context;
        }
        context = context.upper;
    }
 
    return state;
}
 
/**
 * Gets a context for a `throw` statement.
 *
 * @param {CodePathState} state - A state to get.
 * @returns {TryContext|CodePathState} A context for a `throw` statement.
 */
function getThrowContext(state) {
    let context = state.tryContext;
 
    while (context) {
        if (context.position === "try" ||
            (context.hasFinalizer && context.position === "catch")
        ) {
            return context;
        }
        context = context.upper;
    }
 
    return state;
}
 
/**
 * Removes a given element from a given array.
 *
 * @param {any[]} xs - An array to remove the specific element.
 * @param {any} x - An element to be removed.
 * @returns {void}
 */
function remove(xs, x) {
    xs.splice(xs.indexOf(x), 1);
}
 
/**
 * Disconnect given segments.
 *
 * This is used in a process for switch statements.
 * If there is the "default" chunk before other cases, the order is different
 * between node's and running's.
 *
 * @param {CodePathSegment[]} prevSegments - Forward segments to disconnect.
 * @param {CodePathSegment[]} nextSegments - Backward segments to disconnect.
 * @returns {void}
 */
function removeConnection(prevSegments, nextSegments) {
    for (let i = 0; i < prevSegments.length; ++i) {
        const prevSegment = prevSegments[i];
        const nextSegment = nextSegments[i];
 
        remove(prevSegment.nextSegments, nextSegment);
        remove(prevSegment.allNextSegments, nextSegment);
        remove(nextSegment.prevSegments, prevSegment);
        remove(nextSegment.allPrevSegments, prevSegment);
    }
}
 
/**
 * Creates looping path.
 *
 * @param {CodePathState} state - The instance.
 * @param {CodePathSegment[]} fromSegments - Segments which are source.
 * @param {CodePathSegment[]} toSegments - Segments which are destination.
 * @returns {void}
 */
function makeLooped(state, fromSegments, toSegments) {
    const end = Math.min(fromSegments.length, toSegments.length);
 
    for (let i = 0; i < end; ++i) {
        const fromSegment = fromSegments[i];
        const toSegment = toSegments[i];
 
        if (toSegment.reachable) {
            fromSegment.nextSegments.push(toSegment);
        }
        if (fromSegment.reachable) {
            toSegment.prevSegments.push(fromSegment);
        }
        fromSegment.allNextSegments.push(toSegment);
        toSegment.allPrevSegments.push(fromSegment);
 
        if (toSegment.allPrevSegments.length >= 2) {
            CodePathSegment.markPrevSegmentAsLooped(toSegment, fromSegment);
        }
 
        state.notifyLooped(fromSegment, toSegment);
    }
}
 
/**
 * Finalizes segments of `test` chunk of a ForStatement.
 *
 * - Adds `false` paths to paths which are leaving from the loop.
 * - Sets `true` paths to paths which go to the body.
 *
 * @param {LoopContext} context - A loop context to modify.
 * @param {ChoiceContext} choiceContext - A choice context of this loop.
 * @param {CodePathSegment[]} head - The current head paths.
 * @returns {void}
 */
function finalizeTestSegmentsOfFor(context, choiceContext, head) {
    if (!choiceContext.processed) {
        choiceContext.trueForkContext.add(head);
        choiceContext.falseForkContext.add(head);
    }
 
    if (context.test !== true) {
        context.brokenForkContext.addAll(choiceContext.falseForkContext);
    }
    context.endOfTestSegments = choiceContext.trueForkContext.makeNext(0, -1);
}
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
/**
 * A class which manages state to analyze code paths.
 */
class CodePathState {
 
    /**
     * @param {IdGenerator} idGenerator - An id generator to generate id for code
     *   path segments.
     * @param {Function} onLooped - A callback function to notify looping.
     */
    constructor(idGenerator, onLooped) {
        this.idGenerator = idGenerator;
        this.notifyLooped = onLooped;
        this.forkContext = ForkContext.newRoot(idGenerator);
        this.choiceContext = null;
        this.switchContext = null;
        this.tryContext = null;
        this.loopContext = null;
        this.breakContext = null;
 
        this.currentSegments = [];
        this.initialSegment = this.forkContext.head[ 0 ];
 
        // returnedSegments and thrownSegments push elements into finalSegments also.
        const final = this.finalSegments = [];
        const returned = this.returnedForkContext = [];
        const thrown = this.thrownForkContext = [];
 
        returned.add = addToReturnedOrThrown.bind(null, returned, thrown, final);
        thrown.add = addToReturnedOrThrown.bind(null, thrown, returned, final);
    }
 
    /**
     * The head segments.
     * @type {CodePathSegment[]}
     */
    get headSegments() {
        return this.forkContext.head;
    }
 
    /**
     * The parent forking context.
     * This is used for the root of new forks.
     * @type {ForkContext}
     */
    get parentForkContext() {
        const current = this.forkContext;
 
        return current && current.upper;
    }
 
    /**
     * Creates and stacks new forking context.
     *
     * @param {boolean} forkLeavingPath - A flag which shows being in a
     *   "finally" block.
     * @returns {ForkContext} The created context.
     */
    pushForkContext(forkLeavingPath) {
        this.forkContext = ForkContext.newEmpty(
            this.forkContext,
            forkLeavingPath
        );
 
        return this.forkContext;
    }
 
    /**
     * Pops and merges the last forking context.
     * @returns {ForkContext} The last context.
     */
    popForkContext() {
        const lastContext = this.forkContext;
 
        this.forkContext = lastContext.upper;
        this.forkContext.replaceHead(lastContext.makeNext(0, -1));
 
        return lastContext;
    }
 
    /**
     * Creates a new path.
     * @returns {void}
     */
    forkPath() {
        this.forkContext.add(this.parentForkContext.makeNext(-1, -1));
    }
 
    /**
     * Creates a bypass path.
     * This is used for such as IfStatement which does not have "else" chunk.
     *
     * @returns {void}
     */
    forkBypassPath() {
        this.forkContext.add(this.parentForkContext.head);
    }
 
    //--------------------------------------------------------------------------
    // ConditionalExpression, LogicalExpression, IfStatement
    //--------------------------------------------------------------------------
 
    /**
     * Creates a context for ConditionalExpression, LogicalExpression,
     * IfStatement, WhileStatement, DoWhileStatement, or ForStatement.
     *
     * LogicalExpressions have cases that it goes different paths between the
     * `true` case and the `false` case.
     *
     * For Example:
     *
     *     if (a || b) {
     *         foo();
     *     } else {
     *         bar();
     *     }
     *
     * In this case, `b` is evaluated always in the code path of the `else`
     * block, but it's not so in the code path of the `if` block.
     * So there are 3 paths.
     *
     *     a -> foo();
     *     a -> b -> foo();
     *     a -> b -> bar();
     *
     * @param {string} kind - A kind string.
     *   If the new context is LogicalExpression's, this is `"&&"` or `"||"`.
     *   If it's IfStatement's or ConditionalExpression's, this is `"test"`.
     *   Otherwise, this is `"loop"`.
     * @param {boolean} isForkingAsResult - A flag that shows that goes different
     *   paths between `true` and `false`.
     * @returns {void}
     */
    pushChoiceContext(kind, isForkingAsResult) {
        this.choiceContext = {
            upper: this.choiceContext,
            kind,
            isForkingAsResult,
            trueForkContext: ForkContext.newEmpty(this.forkContext),
            falseForkContext: ForkContext.newEmpty(this.forkContext),
            processed: false
        };
    }
 
    /**
     * Pops the last choice context and finalizes it.
     *
     * @returns {ChoiceContext} The popped context.
     */
    popChoiceContext() {
        const context = this.choiceContext;
 
        this.choiceContext = context.upper;
 
        const forkContext = this.forkContext;
        const headSegments = forkContext.head;
 
        switch (context.kind) {
            case "&&":
            case "||":
 
                /*
                 * If any result were not transferred from child contexts,
                 * this sets the head segments to both cases.
                 * The head segments are the path of the right-hand operand.
                 */
                if (!context.processed) {
                    context.trueForkContext.add(headSegments);
                    context.falseForkContext.add(headSegments);
                }
 
                /*
                 * Transfers results to upper context if this context is in
                 * test chunk.
                 */
                if (context.isForkingAsResult) {
                    const parentContext = this.choiceContext;
 
                    parentContext.trueForkContext.addAll(context.trueForkContext);
                    parentContext.falseForkContext.addAll(context.falseForkContext);
                    parentContext.processed = true;
 
                    return context;
                }
 
                break;
 
            case "test":
                if (!context.processed) {
 
                    /*
                     * The head segments are the path of the `if` block here.
                     * Updates the `true` path with the end of the `if` block.
                     */
                    context.trueForkContext.clear();
                    context.trueForkContext.add(headSegments);
                } else {
 
                    /*
                     * The head segments are the path of the `else` block here.
                     * Updates the `false` path with the end of the `else`
                     * block.
                     */
                    context.falseForkContext.clear();
                    context.falseForkContext.add(headSegments);
                }
 
                break;
 
            case "loop":
 
                /*
                 * Loops are addressed in popLoopContext().
                 * This is called from popLoopContext().
                 */
                return context;
 
            /* istanbul ignore next */
            default:
                throw new Error("unreachable");
        }
 
        // Merges all paths.
        const prevForkContext = context.trueForkContext;
 
        prevForkContext.addAll(context.falseForkContext);
        forkContext.replaceHead(prevForkContext.makeNext(0, -1));
 
        return context;
    }
 
    /**
     * Makes a code path segment of the right-hand operand of a logical
     * expression.
     *
     * @returns {void}
     */
    makeLogicalRight() {
        const context = this.choiceContext;
        const forkContext = this.forkContext;
 
        if (context.processed) {
 
            /*
             * This got segments already from the child choice context.
             * Creates the next path from own true/false fork context.
             */
            const prevForkContext =
                context.kind === "&&" ? context.trueForkContext
                /* kind === "||" */ : context.falseForkContext;
 
            forkContext.replaceHead(prevForkContext.makeNext(0, -1));
            prevForkContext.clear();
 
            context.processed = false;
        } else {
 
            /*
             * This did not get segments from the child choice context.
             * So addresses the head segments.
             * The head segments are the path of the left-hand operand.
             */
            if (context.kind === "&&") {
 
                // The path does short-circuit if false.
                context.falseForkContext.add(forkContext.head);
            } else {
 
                // The path does short-circuit if true.
                context.trueForkContext.add(forkContext.head);
            }
 
            forkContext.replaceHead(forkContext.makeNext(-1, -1));
        }
    }
 
    /**
     * Makes a code path segment of the `if` block.
     *
     * @returns {void}
     */
    makeIfConsequent() {
        const context = this.choiceContext;
        const forkContext = this.forkContext;
 
        /*
         * If any result were not transferred from child contexts,
         * this sets the head segments to both cases.
         * The head segments are the path of the test expression.
         */
        if (!context.processed) {
            context.trueForkContext.add(forkContext.head);
            context.falseForkContext.add(forkContext.head);
        }
 
        context.processed = false;
 
        // Creates new path from the `true` case.
        forkContext.replaceHead(
            context.trueForkContext.makeNext(0, -1)
        );
    }
 
    /**
     * Makes a code path segment of the `else` block.
     *
     * @returns {void}
     */
    makeIfAlternate() {
        const context = this.choiceContext;
        const forkContext = this.forkContext;
 
        /*
         * The head segments are the path of the `if` block.
         * Updates the `true` path with the end of the `if` block.
         */
        context.trueForkContext.clear();
        context.trueForkContext.add(forkContext.head);
        context.processed = true;
 
        // Creates new path from the `false` case.
        forkContext.replaceHead(
            context.falseForkContext.makeNext(0, -1)
        );
    }
 
    //--------------------------------------------------------------------------
    // SwitchStatement
    //--------------------------------------------------------------------------
 
    /**
     * Creates a context object of SwitchStatement and stacks it.
     *
     * @param {boolean} hasCase - `true` if the switch statement has one or more
     *   case parts.
     * @param {string|null} label - The label text.
     * @returns {void}
     */
    pushSwitchContext(hasCase, label) {
        this.switchContext = {
            upper: this.switchContext,
            hasCase,
            defaultSegments: null,
            defaultBodySegments: null,
            foundDefault: false,
            lastIsDefault: false,
            countForks: 0
        };
 
        this.pushBreakContext(true, label);
    }
 
    /**
     * Pops the last context of SwitchStatement and finalizes it.
     *
     * - Disposes all forking stack for `case` and `default`.
     * - Creates the next code path segment from `context.brokenForkContext`.
     * - If the last `SwitchCase` node is not a `default` part, creates a path
     *   to the `default` body.
     *
     * @returns {void}
     */
    popSwitchContext() {
        const context = this.switchContext;
 
        this.switchContext = context.upper;
 
        const forkContext = this.forkContext;
        const brokenForkContext = this.popBreakContext().brokenForkContext;
 
        if (context.countForks === 0) {
 
            /*
             * When there is only one `default` chunk and there is one or more
             * `break` statements, even if forks are nothing, it needs to merge
             * those.
             */
            if (!brokenForkContext.empty) {
                brokenForkContext.add(forkContext.makeNext(-1, -1));
                forkContext.replaceHead(brokenForkContext.makeNext(0, -1));
            }
 
            return;
        }
 
        const lastSegments = forkContext.head;
 
        this.forkBypassPath();
        const lastCaseSegments = forkContext.head;
 
        /*
         * `brokenForkContext` is used to make the next segment.
         * It must add the last segment into `brokenForkContext`.
         */
        brokenForkContext.add(lastSegments);
 
        /*
         * A path which is failed in all case test should be connected to path
         * of `default` chunk.
         */
        if (!context.lastIsDefault) {
            if (context.defaultBodySegments) {
 
                /*
                 * Remove a link from `default` label to its chunk.
                 * It's false route.
                 */
                removeConnection(context.defaultSegments, context.defaultBodySegments);
                makeLooped(this, lastCaseSegments, context.defaultBodySegments);
            } else {
 
                /*
                 * It handles the last case body as broken if `default` chunk
                 * does not exist.
                 */
                brokenForkContext.add(lastCaseSegments);
            }
        }
 
        // Pops the segment context stack until the entry segment.
        for (let i = 0; i < context.countForks; ++i) {
            this.forkContext = this.forkContext.upper;
        }
 
        /*
         * Creates a path from all brokenForkContext paths.
         * This is a path after switch statement.
         */
        this.forkContext.replaceHead(brokenForkContext.makeNext(0, -1));
    }
 
    /**
     * Makes a code path segment for a `SwitchCase` node.
     *
     * @param {boolean} isEmpty - `true` if the body is empty.
     * @param {boolean} isDefault - `true` if the body is the default case.
     * @returns {void}
     */
    makeSwitchCaseBody(isEmpty, isDefault) {
        const context = this.switchContext;
 
        if (!context.hasCase) {
            return;
        }
 
        /*
         * Merge forks.
         * The parent fork context has two segments.
         * Those are from the current case and the body of the previous case.
         */
        const parentForkContext = this.forkContext;
        const forkContext = this.pushForkContext();
 
        forkContext.add(parentForkContext.makeNext(0, -1));
 
        /*
         * Save `default` chunk info.
         * If the `default` label is not at the last, we must make a path from
         * the last `case` to the `default` chunk.
         */
        if (isDefault) {
            context.defaultSegments = parentForkContext.head;
            if (isEmpty) {
                context.foundDefault = true;
            } else {
                context.defaultBodySegments = forkContext.head;
            }
        } else {
            if (!isEmpty && context.foundDefault) {
                context.foundDefault = false;
                context.defaultBodySegments = forkContext.head;
            }
        }
 
        context.lastIsDefault = isDefault;
        context.countForks += 1;
    }
 
    //--------------------------------------------------------------------------
    // TryStatement
    //--------------------------------------------------------------------------
 
    /**
     * Creates a context object of TryStatement and stacks it.
     *
     * @param {boolean} hasFinalizer - `true` if the try statement has a
     *   `finally` block.
     * @returns {void}
     */
    pushTryContext(hasFinalizer) {
        this.tryContext = {
            upper: this.tryContext,
            position: "try",
            hasFinalizer,
 
            returnedForkContext: hasFinalizer
                ? ForkContext.newEmpty(this.forkContext)
                : null,
 
            thrownForkContext: ForkContext.newEmpty(this.forkContext),
            lastOfTryIsReachable: false,
            lastOfCatchIsReachable: false
        };
    }
 
    /**
     * Pops the last context of TryStatement and finalizes it.
     *
     * @returns {void}
     */
    popTryContext() {
        const context = this.tryContext;
 
        this.tryContext = context.upper;
 
        if (context.position === "catch") {
 
            // Merges two paths from the `try` block and `catch` block merely.
            this.popForkContext();
            return;
        }
 
        /*
         * The following process is executed only when there is the `finally`
         * block.
         */
 
        const returned = context.returnedForkContext;
        const thrown = context.thrownForkContext;
 
        if (returned.empty && thrown.empty) {
            return;
        }
 
        // Separate head to normal paths and leaving paths.
        const headSegments = this.forkContext.head;
 
        this.forkContext = this.forkContext.upper;
        const normalSegments = headSegments.slice(0, headSegments.length / 2 | 0);
        const leavingSegments = headSegments.slice(headSegments.length / 2 | 0);
 
        // Forwards the leaving path to upper contexts.
        if (!returned.empty) {
            getReturnContext(this).returnedForkContext.add(leavingSegments);
        }
        if (!thrown.empty) {
            getThrowContext(this).thrownForkContext.add(leavingSegments);
        }
 
        // Sets the normal path as the next.
        this.forkContext.replaceHead(normalSegments);
 
        // If both paths of the `try` block and the `catch` block are
        // unreachable, the next path becomes unreachable as well.
        if (!context.lastOfTryIsReachable && !context.lastOfCatchIsReachable) {
            this.forkContext.makeUnreachable();
        }
    }
 
    /**
     * Makes a code path segment for a `catch` block.
     *
     * @returns {void}
     */
    makeCatchBlock() {
        const context = this.tryContext;
        const forkContext = this.forkContext;
        const thrown = context.thrownForkContext;
 
        // Update state.
        context.position = "catch";
        context.thrownForkContext = ForkContext.newEmpty(forkContext);
        context.lastOfTryIsReachable = forkContext.reachable;
 
        // Merge thrown paths.
        thrown.add(forkContext.head);
        const thrownSegments = thrown.makeNext(0, -1);
 
        // Fork to a bypass and the merged thrown path.
        this.pushForkContext();
        this.forkBypassPath();
        this.forkContext.add(thrownSegments);
    }
 
    /**
     * Makes a code path segment for a `finally` block.
     *
     * In the `finally` block, parallel paths are created. The parallel paths
     * are used as leaving-paths. The leaving-paths are paths from `return`
     * statements and `throw` statements in a `try` block or a `catch` block.
     *
     * @returns {void}
     */
    makeFinallyBlock() {
        const context = this.tryContext;
        let forkContext = this.forkContext;
        const returned = context.returnedForkContext;
        const thrown = context.thrownForkContext;
        const headOfLeavingSegments = forkContext.head;
 
        // Update state.
        if (context.position === "catch") {
 
            // Merges two paths from the `try` block and `catch` block.
            this.popForkContext();
            forkContext = this.forkContext;
 
            context.lastOfCatchIsReachable = forkContext.reachable;
        } else {
            context.lastOfTryIsReachable = forkContext.reachable;
        }
        context.position = "finally";
 
        if (returned.empty && thrown.empty) {
 
            // This path does not leave.
            return;
        }
 
        /*
         * Create a parallel segment from merging returned and thrown.
         * This segment will leave at the end of this finally block.
         */
        const segments = forkContext.makeNext(-1, -1);
        let j;
 
        for (let i = 0; i < forkContext.count; ++i) {
            const prevSegsOfLeavingSegment = [headOfLeavingSegments[i]];
 
            for (j = 0; j < returned.segmentsList.length; ++j) {
                prevSegsOfLeavingSegment.push(returned.segmentsList[j][i]);
            }
            for (j = 0; j < thrown.segmentsList.length; ++j) {
                prevSegsOfLeavingSegment.push(thrown.segmentsList[j][i]);
            }
 
            segments.push(CodePathSegment.newNext(
                this.idGenerator.next(),
                prevSegsOfLeavingSegment));
        }
 
        this.pushForkContext(true);
        this.forkContext.add(segments);
    }
 
    /**
     * Makes a code path segment from the first throwable node to the `catch`
     * block or the `finally` block.
     *
     * @returns {void}
     */
    makeFirstThrowablePathInTryBlock() {
        const forkContext = this.forkContext;
 
        if (!forkContext.reachable) {
            return;
        }
 
        const context = getThrowContext(this);
 
        if (context === this ||
            context.position !== "try" ||
            !context.thrownForkContext.empty
        ) {
            return;
        }
 
        context.thrownForkContext.add(forkContext.head);
        forkContext.replaceHead(forkContext.makeNext(-1, -1));
    }
 
    //--------------------------------------------------------------------------
    // Loop Statements
    //--------------------------------------------------------------------------
 
    /**
     * Creates a context object of a loop statement and stacks it.
     *
     * @param {string} type - The type of the node which was triggered. One of
     *   `WhileStatement`, `DoWhileStatement`, `ForStatement`, `ForInStatement`,
     *   and `ForStatement`.
     * @param {string|null} label - A label of the node which was triggered.
     * @returns {void}
     */
    pushLoopContext(type, label) {
        const forkContext = this.forkContext;
        const breakContext = this.pushBreakContext(true, label);
 
        switch (type) {
            case "WhileStatement":
                this.pushChoiceContext("loop", false);
                this.loopContext = {
                    upper: this.loopContext,
                    type,
                    label,
                    test: void 0,
                    continueDestSegments: null,
                    brokenForkContext: breakContext.brokenForkContext
                };
                break;
 
            case "DoWhileStatement":
                this.pushChoiceContext("loop", false);
                this.loopContext = {
                    upper: this.loopContext,
                    type,
                    label,
                    test: void 0,
                    entrySegments: null,
                    continueForkContext: ForkContext.newEmpty(forkContext),
                    brokenForkContext: breakContext.brokenForkContext
                };
                break;
 
            case "ForStatement":
                this.pushChoiceContext("loop", false);
                this.loopContext = {
                    upper: this.loopContext,
                    type,
                    label,
                    test: void 0,
                    endOfInitSegments: null,
                    testSegments: null,
                    endOfTestSegments: null,
                    updateSegments: null,
                    endOfUpdateSegments: null,
                    continueDestSegments: null,
                    brokenForkContext: breakContext.brokenForkContext
                };
                break;
 
            case "ForInStatement":
            case "ForOfStatement":
                this.loopContext = {
                    upper: this.loopContext,
                    type,
                    label,
                    prevSegments: null,
                    leftSegments: null,
                    endOfLeftSegments: null,
                    continueDestSegments: null,
                    brokenForkContext: breakContext.brokenForkContext
                };
                break;
 
            /* istanbul ignore next */
            default:
                throw new Error(`unknown type: "${type}"`);
        }
    }
 
    /**
     * Pops the last context of a loop statement and finalizes it.
     *
     * @returns {void}
     */
    popLoopContext() {
        const context = this.loopContext;
 
        this.loopContext = context.upper;
 
        const forkContext = this.forkContext;
        const brokenForkContext = this.popBreakContext().brokenForkContext;
        let choiceContext;
 
        // Creates a looped path.
        switch (context.type) {
            case "WhileStatement":
            case "ForStatement":
                choiceContext = this.popChoiceContext();
                makeLooped(
                    this,
                    forkContext.head,
                    context.continueDestSegments);
                break;
 
            case "DoWhileStatement": {
                choiceContext = this.popChoiceContext();
 
                if (!choiceContext.processed) {
                    choiceContext.trueForkContext.add(forkContext.head);
                    choiceContext.falseForkContext.add(forkContext.head);
                }
                if (context.test !== true) {
                    brokenForkContext.addAll(choiceContext.falseForkContext);
                }
 
                // `true` paths go to looping.
                const segmentsList = choiceContext.trueForkContext.segmentsList;
 
                for (let i = 0; i < segmentsList.length; ++i) {
                    makeLooped(
                        this,
                        segmentsList[i],
                        context.entrySegments);
                }
                break;
            }
 
            case "ForInStatement":
            case "ForOfStatement":
                brokenForkContext.add(forkContext.head);
                makeLooped(
                    this,
                    forkContext.head,
                    context.leftSegments);
                break;
 
            /* istanbul ignore next */
            default:
                throw new Error("unreachable");
        }
 
        // Go next.
        if (brokenForkContext.empty) {
            forkContext.replaceHead(forkContext.makeUnreachable(-1, -1));
        } else {
            forkContext.replaceHead(brokenForkContext.makeNext(0, -1));
        }
    }
 
    /**
     * Makes a code path segment for the test part of a WhileStatement.
     *
     * @param {boolean|undefined} test - The test value (only when constant).
     * @returns {void}
     */
    makeWhileTest(test) {
        const context = this.loopContext;
        const forkContext = this.forkContext;
        const testSegments = forkContext.makeNext(0, -1);
 
        // Update state.
        context.test = test;
        context.continueDestSegments = testSegments;
        forkContext.replaceHead(testSegments);
    }
 
    /**
     * Makes a code path segment for the body part of a WhileStatement.
     *
     * @returns {void}
     */
    makeWhileBody() {
        const context = this.loopContext;
        const choiceContext = this.choiceContext;
        const forkContext = this.forkContext;
 
        if (!choiceContext.processed) {
            choiceContext.trueForkContext.add(forkContext.head);
            choiceContext.falseForkContext.add(forkContext.head);
        }
 
        // Update state.
        if (context.test !== true) {
            context.brokenForkContext.addAll(choiceContext.falseForkContext);
        }
        forkContext.replaceHead(choiceContext.trueForkContext.makeNext(0, -1));
    }
 
    /**
     * Makes a code path segment for the body part of a DoWhileStatement.
     *
     * @returns {void}
     */
    makeDoWhileBody() {
        const context = this.loopContext;
        const forkContext = this.forkContext;
        const bodySegments = forkContext.makeNext(-1, -1);
 
        // Update state.
        context.entrySegments = bodySegments;
        forkContext.replaceHead(bodySegments);
    }
 
    /**
     * Makes a code path segment for the test part of a DoWhileStatement.
     *
     * @param {boolean|undefined} test - The test value (only when constant).
     * @returns {void}
     */
    makeDoWhileTest(test) {
        const context = this.loopContext;
        const forkContext = this.forkContext;
 
        context.test = test;
 
        // Creates paths of `continue` statements.
        if (!context.continueForkContext.empty) {
            context.continueForkContext.add(forkContext.head);
            const testSegments = context.continueForkContext.makeNext(0, -1);
 
            forkContext.replaceHead(testSegments);
        }
    }
 
    /**
     * Makes a code path segment for the test part of a ForStatement.
     *
     * @param {boolean|undefined} test - The test value (only when constant).
     * @returns {void}
     */
    makeForTest(test) {
        const context = this.loopContext;
        const forkContext = this.forkContext;
        const endOfInitSegments = forkContext.head;
        const testSegments = forkContext.makeNext(-1, -1);
 
        // Update state.
        context.test = test;
        context.endOfInitSegments = endOfInitSegments;
        context.continueDestSegments = context.testSegments = testSegments;
        forkContext.replaceHead(testSegments);
    }
 
    /**
     * Makes a code path segment for the update part of a ForStatement.
     *
     * @returns {void}
     */
    makeForUpdate() {
        const context = this.loopContext;
        const choiceContext = this.choiceContext;
        const forkContext = this.forkContext;
 
        // Make the next paths of the test.
        if (context.testSegments) {
            finalizeTestSegmentsOfFor(
                context,
                choiceContext,
                forkContext.head);
        } else {
            context.endOfInitSegments = forkContext.head;
        }
 
        // Update state.
        const updateSegments = forkContext.makeDisconnected(-1, -1);
 
        context.continueDestSegments = context.updateSegments = updateSegments;
        forkContext.replaceHead(updateSegments);
    }
 
    /**
     * Makes a code path segment for the body part of a ForStatement.
     *
     * @returns {void}
     */
    makeForBody() {
        const context = this.loopContext;
        const choiceContext = this.choiceContext;
        const forkContext = this.forkContext;
 
        // Update state.
        if (context.updateSegments) {
            context.endOfUpdateSegments = forkContext.head;
 
            // `update` -> `test`
            if (context.testSegments) {
                makeLooped(
                    this,
                    context.endOfUpdateSegments,
                    context.testSegments);
            }
        } else if (context.testSegments) {
            finalizeTestSegmentsOfFor(
                context,
                choiceContext,
                forkContext.head);
        } else {
            context.endOfInitSegments = forkContext.head;
        }
 
        let bodySegments = context.endOfTestSegments;
 
        if (!bodySegments) {
 
            /*
             * If there is not the `test` part, the `body` path comes from the
             * `init` part and the `update` part.
             */
            const prevForkContext = ForkContext.newEmpty(forkContext);
 
            prevForkContext.add(context.endOfInitSegments);
            if (context.endOfUpdateSegments) {
                prevForkContext.add(context.endOfUpdateSegments);
            }
 
            bodySegments = prevForkContext.makeNext(0, -1);
        }
        context.continueDestSegments = context.continueDestSegments || bodySegments;
        forkContext.replaceHead(bodySegments);
    }
 
    /**
     * Makes a code path segment for the left part of a ForInStatement and a
     * ForOfStatement.
     *
     * @returns {void}
     */
    makeForInOfLeft() {
        const context = this.loopContext;
        const forkContext = this.forkContext;
        const leftSegments = forkContext.makeDisconnected(-1, -1);
 
        // Update state.
        context.prevSegments = forkContext.head;
        context.leftSegments = context.continueDestSegments = leftSegments;
        forkContext.replaceHead(leftSegments);
    }
 
    /**
     * Makes a code path segment for the right part of a ForInStatement and a
     * ForOfStatement.
     *
     * @returns {void}
     */
    makeForInOfRight() {
        const context = this.loopContext;
        const forkContext = this.forkContext;
        const temp = ForkContext.newEmpty(forkContext);
 
        temp.add(context.prevSegments);
        const rightSegments = temp.makeNext(-1, -1);
 
        // Update state.
        context.endOfLeftSegments = forkContext.head;
        forkContext.replaceHead(rightSegments);
    }
 
    /**
     * Makes a code path segment for the body part of a ForInStatement and a
     * ForOfStatement.
     *
     * @returns {void}
     */
    makeForInOfBody() {
        const context = this.loopContext;
        const forkContext = this.forkContext;
        const temp = ForkContext.newEmpty(forkContext);
 
        temp.add(context.endOfLeftSegments);
        const bodySegments = temp.makeNext(-1, -1);
 
        // Make a path: `right` -> `left`.
        makeLooped(this, forkContext.head, context.leftSegments);
 
        // Update state.
        context.brokenForkContext.add(forkContext.head);
        forkContext.replaceHead(bodySegments);
    }
 
    //--------------------------------------------------------------------------
    // Control Statements
    //--------------------------------------------------------------------------
 
    /**
     * Creates new context for BreakStatement.
     *
     * @param {boolean} breakable - The flag to indicate it can break by
     *      an unlabeled BreakStatement.
     * @param {string|null} label - The label of this context.
     * @returns {Object} The new context.
     */
    pushBreakContext(breakable, label) {
        this.breakContext = {
            upper: this.breakContext,
            breakable,
            label,
            brokenForkContext: ForkContext.newEmpty(this.forkContext)
        };
        return this.breakContext;
    }
 
    /**
     * Removes the top item of the break context stack.
     *
     * @returns {Object} The removed context.
     */
    popBreakContext() {
        const context = this.breakContext;
        const forkContext = this.forkContext;
 
        this.breakContext = context.upper;
 
        // Process this context here for other than switches and loops.
        if (!context.breakable) {
            const brokenForkContext = context.brokenForkContext;
 
            if (!brokenForkContext.empty) {
                brokenForkContext.add(forkContext.head);
                forkContext.replaceHead(brokenForkContext.makeNext(0, -1));
            }
        }
 
        return context;
    }
 
    /**
     * Makes a path for a `break` statement.
     *
     * It registers the head segment to a context of `break`.
     * It makes new unreachable segment, then it set the head with the segment.
     *
     * @param {string} label - A label of the break statement.
     * @returns {void}
     */
    makeBreak(label) {
        const forkContext = this.forkContext;
 
        if (!forkContext.reachable) {
            return;
        }
 
        const context = getBreakContext(this, label);
 
        /* istanbul ignore else: foolproof (syntax error) */
        if (context) {
            context.brokenForkContext.add(forkContext.head);
        }
 
        forkContext.replaceHead(forkContext.makeUnreachable(-1, -1));
    }
 
    /**
     * Makes a path for a `continue` statement.
     *
     * It makes a looping path.
     * It makes new unreachable segment, then it set the head with the segment.
     *
     * @param {string} label - A label of the continue statement.
     * @returns {void}
     */
    makeContinue(label) {
        const forkContext = this.forkContext;
 
        if (!forkContext.reachable) {
            return;
        }
 
        const context = getContinueContext(this, label);
 
        /* istanbul ignore else: foolproof (syntax error) */
        if (context) {
            if (context.continueDestSegments) {
                makeLooped(this, forkContext.head, context.continueDestSegments);
 
                // If the context is a for-in/of loop, this effects a break also.
                if (context.type === "ForInStatement" ||
                    context.type === "ForOfStatement"
                ) {
                    context.brokenForkContext.add(forkContext.head);
                }
            } else {
                context.continueForkContext.add(forkContext.head);
            }
        }
        forkContext.replaceHead(forkContext.makeUnreachable(-1, -1));
    }
 
    /**
     * Makes a path for a `return` statement.
     *
     * It registers the head segment to a context of `return`.
     * It makes new unreachable segment, then it set the head with the segment.
     *
     * @returns {void}
     */
    makeReturn() {
        const forkContext = this.forkContext;
 
        if (forkContext.reachable) {
            getReturnContext(this).returnedForkContext.add(forkContext.head);
            forkContext.replaceHead(forkContext.makeUnreachable(-1, -1));
        }
    }
 
    /**
     * Makes a path for a `throw` statement.
     *
     * It registers the head segment to a context of `throw`.
     * It makes new unreachable segment, then it set the head with the segment.
     *
     * @returns {void}
     */
    makeThrow() {
        const forkContext = this.forkContext;
 
        if (forkContext.reachable) {
            getThrowContext(this).thrownForkContext.add(forkContext.head);
            forkContext.replaceHead(forkContext.makeUnreachable(-1, -1));
        }
    }
 
    /**
     * Makes the final path.
     * @returns {void}
     */
    makeFinal() {
        const segments = this.currentSegments;
 
        if (segments.length > 0 && segments[0].reachable) {
            this.returnedForkContext.add(segments);
        }
    }
}
 
module.exports = CodePathState;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/code-path-analysis/code-path.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/code-path-analysis/code-path.js

Statements: 6.25% (4 / 64)      Branches: 0% (0 / 35)      Functions: 0% (0 / 11)      Lines: 6.25% (4 / 64)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235                      1 1                                                                                                                                                                                                                                                                                                                           1                                                                                                                           1    
/**
 * @fileoverview A class of the code path.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const CodePathState = require("./code-path-state");
const IdGenerator = require("./id-generator");
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
/**
 * A code path.
 */
class CodePath {
 
    /**
     * @param {string} id - An identifier.
     * @param {CodePath|null} upper - The code path of the upper function scope.
     * @param {Function} onLooped - A callback function to notify looping.
     */
    constructor(id, upper, onLooped) {
 
        /**
         * The identifier of this code path.
         * Rules use it to store additional information of each rule.
         * @type {string}
         */
        this.id = id;
 
        /**
         * The code path of the upper function scope.
         * @type {CodePath|null}
         */
        this.upper = upper;
 
        /**
         * The code paths of nested function scopes.
         * @type {CodePath[]}
         */
        this.childCodePaths = [];
 
        // Initializes internal state.
        Object.defineProperty(
            this,
            "internal",
            { value: new CodePathState(new IdGenerator(`${id}_`), onLooped) });
 
        // Adds this into `childCodePaths` of `upper`.
        if (upper) {
            upper.childCodePaths.push(this);
        }
    }
 
    /**
     * Gets the state of a given code path.
     *
     * @param {CodePath} codePath - A code path to get.
     * @returns {CodePathState} The state of the code path.
     */
    static getState(codePath) {
        return codePath.internal;
    }
 
    /**
     * The initial code path segment.
     * @type {CodePathSegment}
     */
    get initialSegment() {
        return this.internal.initialSegment;
    }
 
    /**
     * Final code path segments.
     * This array is a mix of `returnedSegments` and `thrownSegments`.
     * @type {CodePathSegment[]}
     */
    get finalSegments() {
        return this.internal.finalSegments;
    }
 
    /**
     * Final code path segments which is with `return` statements.
     * This array contains the last path segment if it's reachable.
     * Since the reachable last path returns `undefined`.
     * @type {CodePathSegment[]}
     */
    get returnedSegments() {
        return this.internal.returnedForkContext;
    }
 
    /**
     * Final code path segments which is with `throw` statements.
     * @type {CodePathSegment[]}
     */
    get thrownSegments() {
        return this.internal.thrownForkContext;
    }
 
    /**
     * Current code path segments.
     * @type {CodePathSegment[]}
     */
    get currentSegments() {
        return this.internal.currentSegments;
    }
 
    /**
     * Traverses all segments in this code path.
     *
     *     codePath.traverseSegments(function(segment, controller) {
     *         // do something.
     *     });
     *
     * This method enumerates segments in order from the head.
     *
     * The `controller` object has two methods.
     *
     * - `controller.skip()` - Skip the following segments in this branch.
     * - `controller.break()` - Skip all following segments.
     *
     * @param {Object} [options] - Omittable.
     * @param {CodePathSegment} [options.first] - The first segment to traverse.
     * @param {CodePathSegment} [options.last] - The last segment to traverse.
     * @param {Function} callback - A callback function.
     * @returns {void}
     */
    traverseSegments(options, callback) {
        if (typeof options === "function") {
            callback = options;
            options = null;
        }
 
        options = options || {};
        const startSegment = options.first || this.internal.initialSegment;
        const lastSegment = options.last;
 
        let item = null;
        let index = 0;
        let end = 0;
        let segment = null;
        const visited = Object.create(null);
        const stack = [[startSegment, 0]];
        let skippedSegment = null;
        let broken = false;
        const controller = {
            skip() {
                if (stack.length <= 1) {
                    broken = true;
                } else {
                    skippedSegment = stack[stack.length - 2][0];
                }
            },
            break() {
                broken = true;
            }
        };
 
        /**
         * Checks a given previous segment has been visited.
         * @param {CodePathSegment} prevSegment - A previous segment to check.
         * @returns {boolean} `true` if the segment has been visited.
         */
        function isVisited(prevSegment) {
            return (
                visited[prevSegment.id] ||
                segment.isLoopedPrevSegment(prevSegment)
            );
        }
 
        while (stack.length > 0) {
            item = stack[stack.length - 1];
            segment = item[0];
            index = item[1];
 
            if (index === 0) {
 
                // Skip if this segment has been visited already.
                if (visited[segment.id]) {
                    stack.pop();
                    continue;
                }
 
                // Skip if all previous segments have not been visited.
                if (segment !== startSegment &&
                    segment.prevSegments.length > 0 &&
                    !segment.prevSegments.every(isVisited)
                ) {
                    stack.pop();
                    continue;
                }
 
                // Reset the flag of skipping if all branches have been skipped.
                if (skippedSegment && segment.prevSegments.indexOf(skippedSegment) !== -1) {
                    skippedSegment = null;
                }
                visited[segment.id] = true;
 
                // Call the callback when the first time.
                if (!skippedSegment) {
                    callback.call(this, segment, controller); // eslint-disable-line callback-return
                    if (segment === lastSegment) {
                        controller.skip();
                    }
                    if (broken) {
                        break;
                    }
                }
            }
 
            // Update the stack.
            end = segment.nextSegments.length - 1;
            if (index < end) {
                item[1] += 1;
                stack.push([segment.nextSegments[index], 0]);
            } else if (index === end) {
                item[0] = segment.nextSegments[index];
                item[1] = 0;
            } else {
                stack.pop();
            }
        }
    }
}
 
module.exports = CodePath;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/code-path-analysis/debug-helpers.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/code-path-analysis/debug-helpers.js

Statements: 55.07% (38 / 69)      Branches: 65% (26 / 40)      Functions: 75% (3 / 4)      Lines: 55.07% (38 / 69)      Ignored: 35 statements, 3 functions, 24 branches     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202                      1                       1 1             1                                                 1 1   1 1   1       1                               1           1 1   1 1     1 1   1 1   1   1 1   1     1 1   1 1 1 1       1 1 1 1         1     1     1 1 1                                                                                                                                    
/**
 * @fileoverview Helpers to debug for code path analysis.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const debug = require("debug")("eslint:code-path");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Gets id of a given segment.
 * @param {CodePathSegment} segment - A segment to get.
 * @returns {string} Id of the segment.
 */
/* istanbul ignore next */
function getId(segment) { // eslint-disable-line require-jsdoc
    return segment.id + (segment.reachable ? "" : "!");
}
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
module.exports = {
 
    /**
     * A flag that debug dumping is enabled or not.
     * @type {boolean}
     */
    enabled: debug.enabled,
 
    /**
     * Dumps given objects.
     *
     * @param {...any} args - objects to dump.
     * @returns {void}
     */
    dump: debug,
 
    /**
     * Dumps the current analyzing state.
     *
     * @param {ASTNode} node - A node to dump.
     * @param {CodePathState} state - A state to dump.
     * @param {boolean} leaving - A flag whether or not it's leaving
     * @returns {void}
     */
    dumpState: !debug.enabled ? debug : /* istanbul ignore next */ function(node, state, leaving) {
        for (let i = 0; i < state.currentSegments.length; ++i) {
            const segInternal = state.currentSegments[i].internal;
 
            if (leaving) {
                segInternal.exitNodes.push(node);
            } else {
                segInternal.nodes.push(node);
            }
        }
 
        debug([
            `${state.currentSegments.map(getId).join(",")})`,
            `${node.type}${leaving ? ":exit" : ""}`
        ].join(" "));
    },
 
    /**
     * Dumps a DOT code of a given code path.
     * The DOT code can be visialized with Graphvis.
     *
     * @param {CodePath} codePath - A code path to dump.
     * @returns {void}
     * @see http://www.graphviz.org
     * @see http://www.webgraphviz.com
     */
    dumpDot: !debug.enabled ? debug : /* istanbul ignore next */ function(codePath) {
        let text =
            "\n" +
            "digraph {\n" +
            "node[shape=box,style=\"rounded,filled\",fillcolor=white];\n" +
            "initial[label=\"\",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];\n";
 
        if (codePath.returnedSegments.length > 0) {
            text += "final[label=\"\",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];\n";
        }
        if (codePath.thrownSegments.length > 0) {
            text += "thrown[label=\"✘\",shape=circle,width=0.3,height=0.3,fixedsize];\n";
        }
 
        const traceMap = Object.create(null);
        const arrows = this.makeDotArrows(codePath, traceMap);
 
        for (const id in traceMap) { // eslint-disable-line guard-for-in
            const segment = traceMap[id];
 
            text += `${id}[`;
 
            if (segment.reachable) {
                text += "label=\"";
            } else {
                text += "style=\"rounded,dashed,filled\",fillcolor=\"#FF9800\",label=\"<<unreachable>>\\n";
            }
 
            if (segment.internal.nodes.length > 0 || segment.internal.exitNodes.length > 0) {
                text += [].concat(
                    segment.internal.nodes.map(node => {
                        switch (node.type) {
                            case "Identifier": return `${node.type} (${node.name})`;
                            case "Literal": return `${node.type} (${node.value})`;
                            default: return node.type;
                        }
                    }),
                    segment.internal.exitNodes.map(node => {
                        switch (node.type) {
                            case "Identifier": return `${node.type}:exit (${node.name})`;
                            case "Literal": return `${node.type}:exit (${node.value})`;
                            default: return `${node.type}:exit`;
                        }
                    })
                ).join("\\n");
            } else {
                text += "????";
            }
 
            text += "\"];\n";
        }
 
        text += `${arrows}\n`;
        text += "}";
        debug("DOT", text);
    },
 
    /**
     * Makes a DOT code of a given code path.
     * The DOT code can be visialized with Graphvis.
     *
     * @param {CodePath} codePath - A code path to make DOT.
     * @param {Object} traceMap - Optional. A map to check whether or not segments had been done.
     * @returns {string} A DOT code of the code path.
     */
    makeDotArrows(codePath, traceMap) {
        const stack = [[codePath.initialSegment, 0]];
        const done = traceMap || Object.create(null);
        let lastId = codePath.initialSegment.id;
        let text = `initial->${codePath.initialSegment.id}`;
 
        while (stack.length > 0) {
            const item = stack.pop();
            const segment = item[0];
            const index = item[1];
 
            if (done[segment.id] && index === 0) {
                continue;
            }
            done[segment.id] = segment;
 
            const nextSegment = segment.allNextSegments[index];
 
            if (!nextSegment) {
                continue;
            }
 
            if (lastId === segment.id) {
                text += `->${nextSegment.id}`;
            } else {
                text += `;\n${segment.id}->${nextSegment.id}`;
            }
            lastId = nextSegment.id;
 
            stack.unshift([segment, 1 + index]);
            stack.push([nextSegment, 0]);
        }
 
        codePath.returnedSegments.forEach(finalSegment => {
            if (lastId === finalSegment.id) {
                text += "->final";
            } else {
                text += `;\n${finalSegment.id}->final`;
            }
            lastId = null;
        });
 
        codePath.thrownSegments.forEach(finalSegment => {
            if (lastId === finalSegment.id) {
                text += "->thrown";
            } else {
                text += `;\n${finalSegment.id}->thrown`;
            }
            lastId = null;
        });
 
        return `${text};`;
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/code-path-analysis/fork-context.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/code-path-analysis/fork-context.js

Statements: 10.2% (5 / 49)      Branches: 0% (0 / 10)      Functions: 0% (0 / 16)      Lines: 10.2% (5 / 49)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263                              1                         1                                 1                                                                     1                                                                                                                                                                                                                                                                                                                                                                       1    
/**
 * @fileoverview A class to operate forking.
 *
 * This is state of forking.
 * This has a fork list and manages it.
 *
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const assert = require("assert"),
    CodePathSegment = require("./code-path-segment");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Gets whether or not a given segment is reachable.
 *
 * @param {CodePathSegment} segment - A segment to get.
 * @returns {boolean} `true` if the segment is reachable.
 */
function isReachable(segment) {
    return segment.reachable;
}
 
/**
 * Creates new segments from the specific range of `context.segmentsList`.
 *
 * When `context.segmentsList` is `[[a, b], [c, d], [e, f]]`, `begin` is `0`, and
 * `end` is `-1`, this creates `[g, h]`. This `g` is from `a`, `c`, and `e`.
 * This `h` is from `b`, `d`, and `f`.
 *
 * @param {ForkContext} context - An instance.
 * @param {number} begin - The first index of the previous segments.
 * @param {number} end - The last index of the previous segments.
 * @param {Function} create - A factory function of new segments.
 * @returns {CodePathSegment[]} New segments.
 */
function makeSegments(context, begin, end, create) {
    const list = context.segmentsList;
 
    if (begin < 0) {
        begin = list.length + begin;
    }
    if (end < 0) {
        end = list.length + end;
    }
 
    const segments = [];
 
    for (let i = 0; i < context.count; ++i) {
        const allPrevSegments = [];
 
        for (let j = begin; j <= end; ++j) {
            allPrevSegments.push(list[j][i]);
        }
 
        segments.push(create(context.idGenerator.next(), allPrevSegments));
    }
 
    return segments;
}
 
/**
 * `segments` becomes doubly in a `finally` block. Then if a code path exits by a
 * control statement (such as `break`, `continue`) from the `finally` block, the
 * destination's segments may be half of the source segments. In that case, this
 * merges segments.
 *
 * @param {ForkContext} context - An instance.
 * @param {CodePathSegment[]} segments - Segments to merge.
 * @returns {CodePathSegment[]} The merged segments.
 */
function mergeExtraSegments(context, segments) {
    while (segments.length > context.count) {
        const merged = [];
 
        for (let i = 0, length = segments.length / 2 | 0; i < length; ++i) {
            merged.push(CodePathSegment.newNext(
                context.idGenerator.next(),
                [segments[i], segments[i + length]]
            ));
        }
        segments = merged;
    }
    return segments;
}
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
/**
 * A class to manage forking.
 */
class ForkContext {
 
    /**
     * @param {IdGenerator} idGenerator - An identifier generator for segments.
     * @param {ForkContext|null} upper - An upper fork context.
     * @param {number} count - A number of parallel segments.
     */
    constructor(idGenerator, upper, count) {
        this.idGenerator = idGenerator;
        this.upper = upper;
        this.count = count;
        this.segmentsList = [];
    }
 
    /**
     * The head segments.
     * @type {CodePathSegment[]}
     */
    get head() {
        const list = this.segmentsList;
 
        return list.length === 0 ? [] : list[list.length - 1];
    }
 
    /**
     * A flag which shows empty.
     * @type {boolean}
     */
    get empty() {
        return this.segmentsList.length === 0;
    }
 
    /**
     * A flag which shows reachable.
     * @type {boolean}
     */
    get reachable() {
        const segments = this.head;
 
        return segments.length > 0 && segments.some(isReachable);
    }
 
    /**
     * Creates new segments from this context.
     *
     * @param {number} begin - The first index of previous segments.
     * @param {number} end - The last index of previous segments.
     * @returns {CodePathSegment[]} New segments.
     */
    makeNext(begin, end) {
        return makeSegments(this, begin, end, CodePathSegment.newNext);
    }
 
    /**
     * Creates new segments from this context.
     * The new segments is always unreachable.
     *
     * @param {number} begin - The first index of previous segments.
     * @param {number} end - The last index of previous segments.
     * @returns {CodePathSegment[]} New segments.
     */
    makeUnreachable(begin, end) {
        return makeSegments(this, begin, end, CodePathSegment.newUnreachable);
    }
 
    /**
     * Creates new segments from this context.
     * The new segments don't have connections for previous segments.
     * But these inherit the reachable flag from this context.
     *
     * @param {number} begin - The first index of previous segments.
     * @param {number} end - The last index of previous segments.
     * @returns {CodePathSegment[]} New segments.
     */
    makeDisconnected(begin, end) {
        return makeSegments(this, begin, end, CodePathSegment.newDisconnected);
    }
 
    /**
     * Adds segments into this context.
     * The added segments become the head.
     *
     * @param {CodePathSegment[]} segments - Segments to add.
     * @returns {void}
     */
    add(segments) {
        assert(segments.length >= this.count, `${segments.length} >= ${this.count}`);
 
        this.segmentsList.push(mergeExtraSegments(this, segments));
    }
 
    /**
     * Replaces the head segments with given segments.
     * The current head segments are removed.
     *
     * @param {CodePathSegment[]} segments - Segments to add.
     * @returns {void}
     */
    replaceHead(segments) {
        assert(segments.length >= this.count, `${segments.length} >= ${this.count}`);
 
        this.segmentsList.splice(-1, 1, mergeExtraSegments(this, segments));
    }
 
    /**
     * Adds all segments of a given fork context into this context.
     *
     * @param {ForkContext} context - A fork context to add.
     * @returns {void}
     */
    addAll(context) {
        assert(context.count === this.count);
 
        const source = context.segmentsList;
 
        for (let i = 0; i < source.length; ++i) {
            this.segmentsList.push(source[i]);
        }
    }
 
    /**
     * Clears all secments in this context.
     *
     * @returns {void}
     */
    clear() {
        this.segmentsList = [];
    }
 
    /**
     * Creates the root fork context.
     *
     * @param {IdGenerator} idGenerator - An identifier generator for segments.
     * @returns {ForkContext} New fork context.
     */
    static newRoot(idGenerator) {
        const context = new ForkContext(idGenerator, null, 1);
 
        context.add([CodePathSegment.newRoot(idGenerator.next())]);
 
        return context;
    }
 
    /**
     * Creates an empty fork context preceded by a given context.
     *
     * @param {ForkContext} parentContext - The parent fork context.
     * @param {boolean} forkLeavingPath - A flag which shows inside of `finally` block.
     * @returns {ForkContext} New fork context.
     */
    static newEmpty(parentContext, forkLeavingPath) {
        return new ForkContext(
            parentContext.idGenerator,
            parentContext,
            (forkLeavingPath ? 2 : 1) * parentContext.count);
    }
}
 
module.exports = ForkContext;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/code-path-analysis/id-generator.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/code-path-analysis/id-generator.js

Statements: 28.57% (2 / 7)      Branches: 50% (1 / 2)      Functions: 0% (0 / 2)      Lines: 28.57% (2 / 7)      Ignored: 1 statement, 1 branch     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48                                                                            1             1    
/**
 * @fileoverview A class of identifiers generator for code path segments.
 *
 * Each rule uses the identifier of code path segments to store additional
 * information of the code path.
 *
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
/**
 * A generator for unique ids.
 */
class IdGenerator {
 
    /**
     * @param {string} prefix - Optional. A prefix of generated ids.
     */
    constructor(prefix) {
        this.prefix = String(prefix);
        this.n = 0;
    }
 
    /**
     * Generates id.
     *
     * @returns {string} A generated id.
     */
    next() {
        this.n = 1 + this.n | 0;
 
        /* istanbul ignore if */
        if (this.n < 0) {
            this.n = 1;
        }
 
        return this.prefix + this.n;
    }
}
 
module.exports = IdGenerator;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/config/

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/config/

Statements: 15.64% (56 / 358)      Branches: 0.43% (1 / 235)      Functions: 1.96% (1 / 51)      Lines: 15.77% (56 / 355)      Ignored: 1 branch     

All files » node-npmtest-eslint/node_modules/eslint/lib/config/
File Statements Branches Functions Lines
config-file.js 14.86% (26 / 175) 1.22% (1 / 82) 0% (0 / 22) 14.86% (26 / 175)
config-ops.js 7.41% (6 / 81) 0% (0 / 92) 0% (0 / 9) 7.59% (6 / 79)
config-validator.js 19.15% (9 / 47) 0% (0 / 47) 0% (0 / 6) 19.57% (9 / 46)
environments.js 50% (7 / 14) 0% (0 / 4) 20% (1 / 5) 50% (7 / 14)
plugins.js 19.51% (8 / 41) 0% (0 / 10) 0% (0 / 9) 19.51% (8 / 41)
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/config/config-file.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/config/config-file.js

Statements: 14.86% (26 / 175)      Branches: 1.22% (1 / 82)      Functions: 0% (0 / 22)      Lines: 14.86% (26 / 175)      Ignored: 1 branch     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615                          1                             1                             1               1                 1               1                       1                     1                                               1                                     1                                           1                                   1                                 1                                 1                                                                                         1                             1                                   1                               1                                                       1                                                 1                       1                                                             1                                                                                                   1                                                                                               1                                                                   1                                                                                                         1                                                              
/**
 * @fileoverview Helper to locate and load configuration files.
 * @author Nicholas C. Zakas
 */
 
/* eslint no-use-before-define: 0 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const fs = require("fs"),
    path = require("path"),
    shell = require("shelljs"),
    ConfigOps = require("./config-ops"),
    validator = require("./config-validator"),
    Plugins = require("./plugins"),
    pathUtil = require("../util/path-util"),
    ModuleResolver = require("../util/module-resolver"),
    pathIsInside = require("path-is-inside"),
    stripBom = require("strip-bom"),
    stripComments = require("strip-json-comments"),
    stringify = require("json-stable-stringify"),
    defaultOptions = require("../../conf/eslint-recommended"),
    requireUncached = require("require-uncached");
 
const debug = require("debug")("eslint:config-file");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Determines sort order for object keys for json-stable-stringify
 *
 * see: https://github.com/substack/json-stable-stringify#cmp
 *
 * @param   {Object} a The first comparison object ({key: akey, value: avalue})
 * @param   {Object} b The second comparison object ({key: bkey, value: bvalue})
 * @returns {number}   1 or -1, used in stringify cmp method
 */
function sortByKey(a, b) {
    return a.key > b.key ? 1 : -1;
}
 
//------------------------------------------------------------------------------
// Private
//------------------------------------------------------------------------------
 
const CONFIG_FILES = [
    ".eslintrc.js",
    ".eslintrc.yaml",
    ".eslintrc.yml",
    ".eslintrc.json",
    ".eslintrc",
    "package.json"
];
 
const resolver = new ModuleResolver();
 
/**
 * Convenience wrapper for synchronously reading file contents.
 * @param {string} filePath The filename to read.
 * @returns {string} The file contents.
 * @private
 */
function readFile(filePath) {
    return stripBom(fs.readFileSync(filePath, "utf8"));
}
 
/**
 * Determines if a given string represents a filepath or not using the same
 * conventions as require(), meaning that the first character must be nonalphanumeric
 * and not the @ sign which is used for scoped packages to be considered a file path.
 * @param {string} filePath The string to check.
 * @returns {boolean} True if it's a filepath, false if not.
 * @private
 */
function isFilePath(filePath) {
    return path.isAbsolute(filePath) || !/\w|@/.test(filePath.charAt(0));
}
 
/**
 * Loads a YAML configuration from a file.
 * @param {string} filePath The filename to load.
 * @returns {Object} The configuration object from the file.
 * @throws {Error} If the file cannot be read.
 * @private
 */
function loadYAMLConfigFile(filePath) {
    debug(`Loading YAML config file: ${filePath}`);
 
    // lazy load YAML to improve performance when not used
    const yaml = require("js-yaml");
 
    try {
 
        // empty YAML file can be null, so always use
        return yaml.safeLoad(readFile(filePath)) || {};
    } catch (e) {
        debug(`Error reading YAML file: ${filePath}`);
        e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
        throw e;
    }
}
 
/**
 * Loads a JSON configuration from a file.
 * @param {string} filePath The filename to load.
 * @returns {Object} The configuration object from the file.
 * @throws {Error} If the file cannot be read.
 * @private
 */
function loadJSONConfigFile(filePath) {
    debug(`Loading JSON config file: ${filePath}`);
 
    try {
        return JSON.parse(stripComments(readFile(filePath)));
    } catch (e) {
        debug(`Error reading JSON file: ${filePath}`);
        e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
        throw e;
    }
}
 
/**
 * Loads a legacy (.eslintrc) configuration from a file.
 * @param {string} filePath The filename to load.
 * @returns {Object} The configuration object from the file.
 * @throws {Error} If the file cannot be read.
 * @private
 */
function loadLegacyConfigFile(filePath) {
    debug(`Loading config file: ${filePath}`);
 
    // lazy load YAML to improve performance when not used
    const yaml = require("js-yaml");
 
    try {
        return yaml.safeLoad(stripComments(readFile(filePath))) || /* istanbul ignore next */ {};
    } catch (e) {
        debug(`Error reading YAML file: ${filePath}`);
        e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
        throw e;
    }
}
 
/**
 * Loads a JavaScript configuration from a file.
 * @param {string} filePath The filename to load.
 * @returns {Object} The configuration object from the file.
 * @throws {Error} If the file cannot be read.
 * @private
 */
function loadJSConfigFile(filePath) {
    debug(`Loading JS config file: ${filePath}`);
    try {
        return requireUncached(filePath);
    } catch (e) {
        debug(`Error reading JavaScript file: ${filePath}`);
        e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
        throw e;
    }
}
 
/**
 * Loads a configuration from a package.json file.
 * @param {string} filePath The filename to load.
 * @returns {Object} The configuration object from the file.
 * @throws {Error} If the file cannot be read.
 * @private
 */
function loadPackageJSONConfigFile(filePath) {
    debug(`Loading package.json config file: ${filePath}`);
    try {
        return loadJSONConfigFile(filePath).eslintConfig || null;
    } catch (e) {
        debug(`Error reading package.json file: ${filePath}`);
        e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
        throw e;
    }
}
 
/**
 * Creates an error to notify about a missing config to extend from.
 * @param {string} configName The name of the missing config.
 * @returns {Error} The error object to throw
 * @private
 */
function configMissingError(configName) {
    const error = new Error(`Failed to load config "${configName}" to extend from.`);
 
    error.messageTemplate = "extend-config-missing";
    error.messageData = {
        configName
    };
    return error;
}
 
/**
 * Loads a configuration file regardless of the source. Inspects the file path
 * to determine the correctly way to load the config file.
 * @param {Object} file The path to the configuration.
 * @returns {Object} The configuration information.
 * @private
 */
function loadConfigFile(file) {
    const filePath = file.filePath;
    let config;
 
    switch (path.extname(filePath)) {
        case ".js":
            config = loadJSConfigFile(filePath);
            if (file.configName) {
                config = config.configs[file.configName];
                if (!config) {
                    throw configMissingError(file.configFullName);
                }
            }
            break;
 
        case ".json":
            if (path.basename(filePath) === "package.json") {
                config = loadPackageJSONConfigFile(filePath);
                if (config === null) {
                    return null;
                }
            } else {
                config = loadJSONConfigFile(filePath);
            }
            break;
 
        case ".yaml":
        case ".yml":
            config = loadYAMLConfigFile(filePath);
            break;
 
        default:
            config = loadLegacyConfigFile(filePath);
    }
 
    return ConfigOps.merge(ConfigOps.createEmptyConfig(), config);
}
 
/**
 * Writes a configuration file in JSON format.
 * @param {Object} config The configuration object to write.
 * @param {string} filePath The filename to write to.
 * @returns {void}
 * @private
 */
function writeJSONConfigFile(config, filePath) {
    debug(`Writing JSON config file: ${filePath}`);
 
    const content = stringify(config, { cmp: sortByKey, space: 4 });
 
    fs.writeFileSync(filePath, content, "utf8");
}
 
/**
 * Writes a configuration file in YAML format.
 * @param {Object} config The configuration object to write.
 * @param {string} filePath The filename to write to.
 * @returns {void}
 * @private
 */
function writeYAMLConfigFile(config, filePath) {
    debug(`Writing YAML config file: ${filePath}`);
 
    // lazy load YAML to improve performance when not used
    const yaml = require("js-yaml");
 
    const content = yaml.safeDump(config, { sortKeys: true });
 
    fs.writeFileSync(filePath, content, "utf8");
}
 
/**
 * Writes a configuration file in JavaScript format.
 * @param {Object} config The configuration object to write.
 * @param {string} filePath The filename to write to.
 * @returns {void}
 * @private
 */
function writeJSConfigFile(config, filePath) {
    debug(`Writing JS config file: ${filePath}`);
 
    const content = `module.exports = ${stringify(config, { cmp: sortByKey, space: 4 })};`;
 
    fs.writeFileSync(filePath, content, "utf8");
}
 
/**
 * Writes a configuration file.
 * @param {Object} config The configuration object to write.
 * @param {string} filePath The filename to write to.
 * @returns {void}
 * @throws {Error} When an unknown file type is specified.
 * @private
 */
function write(config, filePath) {
    switch (path.extname(filePath)) {
        case ".js":
            writeJSConfigFile(config, filePath);
            break;
 
        case ".json":
            writeJSONConfigFile(config, filePath);
            break;
 
        case ".yaml":
        case ".yml":
            writeYAMLConfigFile(config, filePath);
            break;
 
        default:
            throw new Error("Can't write to unknown file type.");
    }
}
 
/**
 * Determines the base directory for node packages referenced in a config file.
 * This does not include node_modules in the path so it can be used for all
 * references relative to a config file.
 * @param {string} configFilePath The config file referencing the file.
 * @returns {string} The base directory for the file path.
 * @private
 */
function getBaseDir(configFilePath) {
 
    // calculates the path of the project including ESLint as dependency
    const projectPath = path.resolve(__dirname, "../../../");
 
    if (configFilePath && pathIsInside(configFilePath, projectPath)) {
 
        // be careful of https://github.com/substack/node-resolve/issues/78
        return path.join(path.resolve(configFilePath));
    }
 
    /*
     * default to ESLint project path since it's unlikely that plugins will be
     * in this directory
     */
    return path.join(projectPath);
}
 
/**
 * Determines the lookup path, including node_modules, for package
 * references relative to a config file.
 * @param {string} configFilePath The config file referencing the file.
 * @returns {string} The lookup path for the file path.
 * @private
 */
function getLookupPath(configFilePath) {
    const basedir = getBaseDir(configFilePath);
 
    return path.join(basedir, "node_modules");
}
 
/**
 * Resolves a eslint core config path
 * @param {string} name The eslint config name.
 * @returns {string} The resolved path of the config.
 * @private
 */
function getEslintCoreConfigPath(name) {
    if (name === "eslint:recommended") {
 
       /*
        * Add an explicit substitution for eslint:recommended to
        * conf/eslint-recommended.js.
        */
        return path.resolve(__dirname, "../../conf/eslint-recommended.js");
    }
 
    if (name === "eslint:all") {
 
       /*
        * Add an explicit substitution for eslint:all to conf/eslint-all.js
        */
        return path.resolve(__dirname, "../../conf/eslint-all.js");
    }
 
    throw configMissingError(name);
}
 
/**
 * Applies values from the "extends" field in a configuration file.
 * @param {Object} config The configuration information.
 * @param {string} filePath The file path from which the configuration information
 *      was loaded.
 * @param {string} [relativeTo] The path to resolve relative to.
 * @returns {Object} A new configuration object with all of the "extends" fields
 *      loaded and merged.
 * @private
 */
function applyExtends(config, filePath, relativeTo) {
    let configExtends = config.extends;
 
    // normalize into an array for easier handling
    if (!Array.isArray(config.extends)) {
        configExtends = [config.extends];
    }
 
    // Make the last element in an array take the highest precedence
    config = configExtends.reduceRight((previousValue, parentPath) => {
        try {
            if (parentPath.startsWith("eslint:")) {
                parentPath = getEslintCoreConfigPath(parentPath);
            } else if (isFilePath(parentPath)) {
 
                /*
                 * If the `extends` path is relative, use the directory of the current configuration
                 * file as the reference point. Otherwise, use as-is.
                 */
                parentPath = (path.isAbsolute(parentPath)
                    ? parentPath
                    : path.join(relativeTo || path.dirname(filePath), parentPath)
                );
            }
            debug(`Loading ${parentPath}`);
            return ConfigOps.merge(load(parentPath, false, relativeTo), previousValue);
        } catch (e) {
 
            /*
             * If the file referenced by `extends` failed to load, add the path
             * to the configuration file that referenced it to the error
             * message so the user is able to see where it was referenced from,
             * then re-throw.
             */
            e.message += `\nReferenced from: ${filePath}`;
            throw e;
        }
 
    }, config);
 
    return config;
}
 
/**
 * Brings package name to correct format based on prefix
 * @param {string} name The name of the package.
 * @param {string} prefix Can be either "eslint-plugin" or "eslint-config
 * @returns {string} Normalized name of the package
 * @private
 */
function normalizePackageName(name, prefix) {
 
    /*
     * On Windows, name can come in with Windows slashes instead of Unix slashes.
     * Normalize to Unix first to avoid errors later on.
     * https://github.com/eslint/eslint/issues/5644
     */
    if (name.indexOf("\\") > -1) {
        name = pathUtil.convertPathToPosix(name);
    }
 
    if (name.charAt(0) === "@") {
 
        /*
         * it's a scoped package
         * package name is "eslint-config", or just a username
         */
        const scopedPackageShortcutRegex = new RegExp(`^(@[^/]+)(?:/(?:${prefix})?)?$`),
            scopedPackageNameRegex = new RegExp(`^${prefix}(-|$)`);
 
        if (scopedPackageShortcutRegex.test(name)) {
            name = name.replace(scopedPackageShortcutRegex, `$1/${prefix}`);
        } else if (!scopedPackageNameRegex.test(name.split("/")[1])) {
 
            /*
             * for scoped packages, insert the eslint-config after the first / unless
             * the path is already @scope/eslint or @scope/eslint-config-xxx
             */
            name = name.replace(/^@([^/]+)\/(.*)$/, `@$1/${prefix}-$2`);
        }
    } else if (name.indexOf(`${prefix}-`) !== 0) {
        name = `${prefix}-${name}`;
    }
 
    return name;
}
 
/**
 * Resolves a configuration file path into the fully-formed path, whether filename
 * or package name.
 * @param {string} filePath The filepath to resolve.
 * @param {string} [relativeTo] The path to resolve relative to.
 * @returns {Object} An object containing 3 properties:
 * - 'filePath' (required) the resolved path that can be used directly to load the configuration.
 * - 'configName' the name of the configuration inside the plugin.
 * - 'configFullName' the name of the configuration as used in the eslint config (e.g. 'plugin:node/recommended').
 * @private
 */
function resolve(filePath, relativeTo) {
    if (isFilePath(filePath)) {
        return { filePath: path.resolve(relativeTo || "", filePath) };
    }
    let normalizedPackageName;
 
    if (filePath.startsWith("plugin:")) {
        const configFullName = filePath;
        const pluginName = filePath.substr(7, filePath.lastIndexOf("/") - 7);
        const configName = filePath.substr(filePath.lastIndexOf("/") + 1, filePath.length - filePath.lastIndexOf("/") - 1);
 
        normalizedPackageName = normalizePackageName(pluginName, "eslint-plugin");
        debug(`Attempting to resolve ${normalizedPackageName}`);
        filePath = resolver.resolve(normalizedPackageName, getLookupPath(relativeTo));
        return { filePath, configName, configFullName };
    }
    normalizedPackageName = normalizePackageName(filePath, "eslint-config");
    debug(`Attempting to resolve ${normalizedPackageName}`);
    filePath = resolver.resolve(normalizedPackageName, getLookupPath(relativeTo));
    return { filePath };
 
 
 
}
 
/**
 * Loads a configuration file from the given file path.
 * @param {string} filePath The filename or package name to load the configuration
 *      information from.
 * @param {boolean} [applyEnvironments=false] Set to true to merge in environment settings.
 * @param {string} [relativeTo] The path to resolve relative to.
 * @returns {Object} The configuration information.
 * @private
 */
function load(filePath, applyEnvironments, relativeTo) {
    const resolvedPath = resolve(filePath, relativeTo),
        dirname = path.dirname(resolvedPath.filePath),
        lookupPath = getLookupPath(dirname);
    let config = loadConfigFile(resolvedPath);
 
    if (config) {
 
        // ensure plugins are properly loaded first
        if (config.plugins) {
            Plugins.loadAll(config.plugins);
        }
 
        // remove parser from config if it is the default parser
        if (config.parser === defaultOptions.parser) {
            config.parser = null;
        }
 
        // include full path of parser if present
        if (config.parser) {
            if (isFilePath(config.parser)) {
                config.parser = path.resolve(dirname || "", config.parser);
            } else {
                config.parser = resolver.resolve(config.parser, lookupPath);
            }
        }
 
        // validate the configuration before continuing
        validator.validate(config, filePath);
 
        /*
         * If an `extends` property is defined, it represents a configuration file to use as
         * a "parent". Load the referenced file and merge the configuration recursively.
         */
        if (config.extends) {
            config = applyExtends(config, filePath, dirname);
        }
 
        if (config.env && applyEnvironments) {
 
            // Merge in environment-specific globals and parserOptions.
            config = ConfigOps.applyEnvironments(config);
        }
 
    }
 
    return config;
}
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
module.exports = {
 
    getBaseDir,
    getLookupPath,
    load,
    resolve,
    write,
    applyExtends,
    normalizePackageName,
    CONFIG_FILES,
 
    /**
     * Retrieves the configuration filename for a given directory. It loops over all
     * of the valid configuration filenames in order to find the first one that exists.
     * @param {string} directory The directory to check for a config file.
     * @returns {?string} The filename of the configuration file for the directory
     *      or null if there is no configuration file in the directory.
     */
    getFilenameForDirectory(directory) {
        for (let i = 0, len = CONFIG_FILES.length; i < len; i++) {
            const filename = path.join(directory, CONFIG_FILES[i]);
 
            if (shell.test("-f", filename)) {
                return filename;
            }
        }
 
        return null;
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/config/config-ops.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/config/config-ops.js

Statements: 7.41% (6 / 81)      Branches: 0% (0 / 92)      Functions: 0% (0 / 9)      Lines: 7.59% (6 / 79)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274                      1   1           1   3 3               1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
/**
 * @fileoverview Config file operations. This file must be usable in the browser,
 * so no Node-specific code can be here.
 * @author Nicholas C. Zakas
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const Environments = require("./environments");
 
const debug = require("debug")("eslint:config-ops");
 
//------------------------------------------------------------------------------
// Private
//------------------------------------------------------------------------------
 
const RULE_SEVERITY_STRINGS = ["off", "warn", "error"],
    RULE_SEVERITY = RULE_SEVERITY_STRINGS.reduce((map, value, index) => {
        map[value] = index;
        return map;
    }, {}),
    VALID_SEVERITIES = [0, 1, 2, "off", "warn", "error"];
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
module.exports = {
 
    /**
     * Creates an empty configuration object suitable for merging as a base.
     * @returns {Object} A configuration object.
     */
    createEmptyConfig() {
        return {
            globals: {},
            env: {},
            rules: {},
            parserOptions: {}
        };
    },
 
    /**
     * Creates an environment config based on the specified environments.
     * @param {Object<string,boolean>} env The environment settings.
     * @returns {Object} A configuration object with the appropriate rules and globals
     *      set.
     */
    createEnvironmentConfig(env) {
 
        const envConfig = this.createEmptyConfig();
 
        if (env) {
 
            envConfig.env = env;
 
            Object.keys(env).filter(name => env[name]).forEach(name => {
                const environment = Environments.get(name);
 
                if (environment) {
                    debug(`Creating config for environment ${name}`);
                    if (environment.globals) {
                        Object.assign(envConfig.globals, environment.globals);
                    }
 
                    if (environment.parserOptions) {
                        Object.assign(envConfig.parserOptions, environment.parserOptions);
                    }
                }
            });
        }
 
        return envConfig;
    },
 
    /**
     * Given a config with environment settings, applies the globals and
     * ecmaFeatures to the configuration and returns the result.
     * @param {Object} config The configuration information.
     * @returns {Object} The updated configuration information.
     */
    applyEnvironments(config) {
        if (config.env && typeof config.env === "object") {
            debug("Apply environment settings to config");
            return this.merge(this.createEnvironmentConfig(config.env), config);
        }
 
        return config;
    },
 
    /**
     * Merges two config objects. This will not only add missing keys, but will also modify values to match.
     * @param {Object} target config object
     * @param {Object} src config object. Overrides in this config object will take priority over base.
     * @param {boolean} [combine] Whether to combine arrays or not
     * @param {boolean} [isRule] Whether its a rule
     * @returns {Object} merged config object.
     */
    merge: function deepmerge(target, src, combine, isRule) {
 
        /*
         The MIT License (MIT)
 
         Copyright (c) 2012 Nicholas Fisher
 
         Permission is hereby granted, free of charge, to any person obtaining a copy
         of this software and associated documentation files (the "Software"), to deal
         in the Software without restriction, including without limitation the rights
         to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         copies of the Software, and to permit persons to whom the Software is
         furnished to do so, subject to the following conditions:
 
         The above copyright notice and this permission notice shall be included in
         all copies or substantial portions of the Software.
 
         THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
         THE SOFTWARE.
         */
 
        /*
         * This code is taken from deepmerge repo
         * (https://github.com/KyleAMathews/deepmerge)
         * and modified to meet our needs.
         */
        const array = Array.isArray(src) || Array.isArray(target);
        let dst = array && [] || {};
 
        combine = !!combine;
        isRule = !!isRule;
        if (array) {
            target = target || [];
 
            // src could be a string, so check for array
            if (isRule && Array.isArray(src) && src.length > 1) {
                dst = dst.concat(src);
            } else {
                dst = dst.concat(target);
            }
            if (typeof src !== "object" && !Array.isArray(src)) {
                src = [src];
            }
            Object.keys(src).forEach((e, i) => {
                e = src[i];
                if (typeof dst[i] === "undefined") {
                    dst[i] = e;
                } else if (typeof e === "object") {
                    if (isRule) {
                        dst[i] = e;
                    } else {
                        dst[i] = deepmerge(target[i], e, combine, isRule);
                    }
                } else {
                    if (!combine) {
                        dst[i] = e;
                    } else {
                        if (dst.indexOf(e) === -1) {
                            dst.push(e);
                        }
                    }
                }
            });
        } else {
            if (target && typeof target === "object") {
                Object.keys(target).forEach(key => {
                    dst[key] = target[key];
                });
            }
            Object.keys(src).forEach(key => {
                if (Array.isArray(src[key]) || Array.isArray(target[key])) {
                    dst[key] = deepmerge(target[key], src[key], key === "plugins", isRule);
                } else if (typeof src[key] !== "object" || !src[key] || key === "exported" || key === "astGlobals") {
                    dst[key] = src[key];
                } else {
                    dst[key] = deepmerge(target[key] || {}, src[key], combine, key === "rules");
                }
            });
        }
 
        return dst;
    },
 
    /**
     * Converts new-style severity settings (off, warn, error) into old-style
     * severity settings (0, 1, 2) for all rules. Assumption is that severity
     * values have already been validated as correct.
     * @param {Object} config The config object to normalize.
     * @returns {void}
     */
    normalize(config) {
 
        if (config.rules) {
            Object.keys(config.rules).forEach(ruleId => {
                const ruleConfig = config.rules[ruleId];
 
                if (typeof ruleConfig === "string") {
                    config.rules[ruleId] = RULE_SEVERITY[ruleConfig.toLowerCase()] || 0;
                } else if (Array.isArray(ruleConfig) && typeof ruleConfig[0] === "string") {
                    ruleConfig[0] = RULE_SEVERITY[ruleConfig[0].toLowerCase()] || 0;
                }
            });
        }
    },
 
    /**
     * Converts old-style severity settings (0, 1, 2) into new-style
     * severity settings (off, warn, error) for all rules. Assumption is that severity
     * values have already been validated as correct.
     * @param {Object} config The config object to normalize.
     * @returns {void}
     */
    normalizeToStrings(config) {
 
        if (config.rules) {
            Object.keys(config.rules).forEach(ruleId => {
                const ruleConfig = config.rules[ruleId];
 
                if (typeof ruleConfig === "number") {
                    config.rules[ruleId] = RULE_SEVERITY_STRINGS[ruleConfig] || RULE_SEVERITY_STRINGS[0];
                } else if (Array.isArray(ruleConfig) && typeof ruleConfig[0] === "number") {
                    ruleConfig[0] = RULE_SEVERITY_STRINGS[ruleConfig[0]] || RULE_SEVERITY_STRINGS[0];
                }
            });
        }
    },
 
    /**
     * Determines if the severity for the given rule configuration represents an error.
     * @param {int|string|Array} ruleConfig The configuration for an individual rule.
     * @returns {boolean} True if the rule represents an error, false if not.
     */
    isErrorSeverity(ruleConfig) {
 
        let severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
 
        if (typeof severity === "string") {
            severity = RULE_SEVERITY[severity.toLowerCase()] || 0;
        }
 
        return (typeof severity === "number" && severity === 2);
    },
 
    /**
     * Checks whether a given config has valid severity or not.
     * @param {number|string|Array} ruleConfig - The configuration for an individual rule.
     * @returns {boolean} `true` if the configuration has valid severity.
     */
    isValidSeverity(ruleConfig) {
        let severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
 
        if (typeof severity === "string") {
            severity = severity.toLowerCase();
        }
        return VALID_SEVERITIES.indexOf(severity) !== -1;
    },
 
    /**
     * Checks whether every rule of a given config has valid severity or not.
     * @param {Object} config - The configuration for rules.
     * @returns {boolean} `true` if the configuration has valid severity.
     */
    isEverySeverityValid(config) {
        return Object.keys(config).every(ruleId => this.isValidSeverity(config[ruleId]));
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/config/config-validator.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/config/config-validator.js

Statements: 19.15% (9 / 47)      Branches: 0% (0 / 47)      Functions: 0% (0 / 6)      Lines: 19.57% (9 / 46)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173                      1         1                         1                                                             1                               1                                               1                                   1                                                                 1                             1            
/**
 * @fileoverview Validates configs.
 * @author Brandon Mills
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const rules = require("../rules"),
    Environments = require("./environments"),
    schemaValidator = require("is-my-json-valid"),
    util = require("util");
 
const validators = {
    rules: Object.create(null)
};
 
//------------------------------------------------------------------------------
// Private
//------------------------------------------------------------------------------
 
/**
 * Gets a complete options schema for a rule.
 * @param {string} id The rule's unique name.
 * @returns {Object} JSON Schema for the rule's options.
 */
function getRuleOptionsSchema(id) {
    const rule = rules.get(id),
        schema = rule && rule.schema || rule && rule.meta && rule.meta.schema;
 
    // Given a tuple of schemas, insert warning level at the beginning
    if (Array.isArray(schema)) {
        if (schema.length) {
            return {
                type: "array",
                items: schema,
                minItems: 0,
                maxItems: schema.length
            };
        }
        return {
            type: "array",
            minItems: 0,
            maxItems: 0
        };
 
    }
 
    // Given a full schema, leave it alone
    return schema || null;
}
 
/**
* Validates a rule's severity and returns the severity value. Throws an error if the severity is invalid.
* @param {options} options The given options for the rule.
* @returns {number|string} The rule's severity value
*/
function validateRuleSeverity(options) {
    const severity = Array.isArray(options) ? options[0] : options;
 
    if (severity !== 0 && severity !== 1 && severity !== 2 && !(typeof severity === "string" && /^(?:off|warn|error)$/i.test(severity))) {
        throw new Error(`\tSeverity should be one of the following: 0 = off, 1 = warn, 2 = error (you passed '${util.inspect(severity).replace(/'/g, "\"").replace(/\n/g, "")}').\n`);
    }
 
    return severity;
}
 
/**
* Validates the non-severity options passed to a rule, based on its schema.
* @param {string} id The rule's unique name
* @param {array} localOptions The options for the rule, excluding severity
* @returns {void}
*/
function validateRuleSchema(id, localOptions) {
    const schema = getRuleOptionsSchema(id);
 
    if (!validators.rules[id] && schema) {
        validators.rules[id] = schemaValidator(schema, { verbose: true });
    }
 
    const validateRule = validators.rules[id];
 
    if (validateRule) {
        validateRule(localOptions);
        if (validateRule.errors) {
            throw new Error(validateRule.errors.map(error => `\tValue "${error.value}" ${error.message}.\n`).join(""));
        }
    }
}
 
/**
 * Validates a rule's options against its schema.
 * @param {string} id The rule's unique name.
 * @param {array|number} options The given options for the rule.
 * @param {string} source The name of the configuration source.
 * @returns {void}
 */
function validateRuleOptions(id, options, source) {
    try {
        const severity = validateRuleSeverity(options);
 
        if (severity !== 0 && !(typeof severity === "string" && severity.toLowerCase() === "off")) {
            validateRuleSchema(id, Array.isArray(options) ? options.slice(1) : []);
        }
    } catch (err) {
        throw new Error(`${source}:\n\tConfiguration for rule "${id}" is invalid:\n${err.message}`);
    }
}
 
/**
 * Validates an environment object
 * @param {Object} environment The environment config object to validate.
 * @param {string} source The location to report with any errors.
 * @returns {void}
 */
function validateEnvironment(environment, source) {
 
    // not having an environment is ok
    if (!environment) {
        return;
    }
 
    if (Array.isArray(environment)) {
        throw new Error("Environment must not be an array");
    }
 
    if (typeof environment === "object") {
        Object.keys(environment).forEach(env => {
            if (!Environments.get(env)) {
                const message = [
                    source, ":\n",
                    "\tEnvironment key \"", env, "\" is unknown\n"
                ];
 
                throw new Error(message.join(""));
            }
        });
    } else {
        throw new Error("Environment must be an object");
    }
}
 
/**
 * Validates an entire config object.
 * @param {Object} config The config object to validate.
 * @param {string} source The location to report with any errors.
 * @returns {void}
 */
function validate(config, source) {
 
    if (typeof config.rules === "object") {
        Object.keys(config.rules).forEach(id => {
            validateRuleOptions(id, config.rules[id], source);
        });
    }
 
    validateEnvironment(config.env, source);
}
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
module.exports = {
    getRuleOptionsSchema,
    validate,
    validateRuleOptions
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/config/environments.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/config/environments.js

Statements: 50% (7 / 14)      Branches: 0% (0 / 4)      Functions: 20% (1 / 5)      Lines: 50% (7 / 14)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84                    1           1             1 1 26         1           1                                                                                              
/**
 * @fileoverview Environments manager
 * @author Nicholas C. Zakas
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const envs = require("../../conf/environments");
 
//------------------------------------------------------------------------------
// Private
//------------------------------------------------------------------------------
 
let environments = new Map();
 
/**
 * Loads the default environments.
 * @returns {void}
 * @private
 */
function load() {
    Object.keys(envs).forEach(envName => {
        environments.set(envName, envs[envName]);
    });
}
 
// always load default environments upfront
load();
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
module.exports = {
 
    load,
 
    /**
     * Gets the environment with the given name.
     * @param {string} name The name of the environment to retrieve.
     * @returns {Object?} The environment object or null if not found.
     */
    get(name) {
        return environments.get(name) || null;
    },
 
    /**
     * Defines an environment.
     * @param {string} name The name of the environment.
     * @param {Object} env The environment settings.
     * @returns {void}
     */
    define(name, env) {
        environments.set(name, env);
    },
 
    /**
     * Imports all environments from a plugin.
     * @param {Object} plugin The plugin object.
     * @param {string} pluginName The name of the plugin.
     * @returns {void}
     */
    importPlugin(plugin, pluginName) {
        if (plugin.environments) {
            Object.keys(plugin.environments).forEach(envName => {
                this.define(`${pluginName}/${envName}`, plugin.environments[envName]);
            });
        }
    },
 
    /**
     * Resets all environments. Only use for tests!
     * @returns {void}
     */
    testReset() {
        environments = new Map();
        load();
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/config/plugins.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/config/plugins.js

Statements: 19.51% (8 / 41)      Branches: 0% (0 / 10)      Functions: 0% (0 / 9)      Lines: 19.51% (8 / 41)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174                    1     1           1   1               1                 1                 1               1                                                                                                                                                                                                                                            
/**
 * @fileoverview Plugins manager
 * @author Nicholas C. Zakas
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const Environments = require("./environments"),
    Rules = require("../rules");
 
const debug = require("debug")("eslint:plugins");
 
//------------------------------------------------------------------------------
// Private
//------------------------------------------------------------------------------
 
let plugins = Object.create(null);
 
const PLUGIN_NAME_PREFIX = "eslint-plugin-",
    NAMESPACE_REGEX = /^@.*\//i;
 
/**
 * Removes the prefix `eslint-plugin-` from a plugin name.
 * @param {string} pluginName The name of the plugin which may have the prefix.
 * @returns {string} The name of the plugin without prefix.
 */
function removePrefix(pluginName) {
    return pluginName.indexOf(PLUGIN_NAME_PREFIX) === 0 ? pluginName.substring(PLUGIN_NAME_PREFIX.length) : pluginName;
}
 
/**
 * Gets the scope (namespace) of a plugin.
 * @param {string} pluginName The name of the plugin which may have the prefix.
 * @returns {string} The name of the plugins namepace if it has one.
 */
function getNamespace(pluginName) {
    return pluginName.match(NAMESPACE_REGEX) ? pluginName.match(NAMESPACE_REGEX)[0] : "";
}
 
/**
 * Removes the namespace from a plugin name.
 * @param {string} pluginName The name of the plugin which may have the prefix.
 * @returns {string} The name of the plugin without the namespace.
 */
function removeNamespace(pluginName) {
    return pluginName.replace(NAMESPACE_REGEX, "");
}
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
module.exports = {
 
    removePrefix,
    getNamespace,
    removeNamespace,
 
    /**
     * Defines a plugin with a given name rather than loading from disk.
     * @param {string} pluginName The name of the plugin to load.
     * @param {Object} plugin The plugin object.
     * @returns {void}
     */
    define(pluginName, plugin) {
        const pluginNamespace = getNamespace(pluginName),
            pluginNameWithoutNamespace = removeNamespace(pluginName),
            pluginNameWithoutPrefix = removePrefix(pluginNameWithoutNamespace),
            shortName = pluginNamespace + pluginNameWithoutPrefix;
 
        // load up environments and rules
        plugins[shortName] = plugin;
        Environments.importPlugin(plugin, shortName);
        Rules.importPlugin(plugin, shortName);
 
        // load up environments and rules for the name that '@scope/' was omitted
        // 3 lines below will be removed by 4.0.0
        plugins[pluginNameWithoutPrefix] = plugin;
        Environments.importPlugin(plugin, pluginNameWithoutPrefix);
        Rules.importPlugin(plugin, pluginNameWithoutPrefix);
    },
 
    /**
     * Gets a plugin with the given name.
     * @param {string} pluginName The name of the plugin to retrieve.
     * @returns {Object} The plugin or null if not loaded.
     */
    get(pluginName) {
        return plugins[pluginName] || null;
    },
 
    /**
     * Returns all plugins that are loaded.
     * @returns {Object} The plugins cache.
     */
    getAll() {
        return plugins;
    },
 
    /**
     * Loads a plugin with the given name.
     * @param {string} pluginName The name of the plugin to load.
     * @returns {void}
     * @throws {Error} If the plugin cannot be loaded.
     */
    load(pluginName) {
        const pluginNamespace = getNamespace(pluginName),
            pluginNameWithoutNamespace = removeNamespace(pluginName),
            pluginNameWithoutPrefix = removePrefix(pluginNameWithoutNamespace),
            shortName = pluginNamespace + pluginNameWithoutPrefix,
            longName = pluginNamespace + PLUGIN_NAME_PREFIX + pluginNameWithoutPrefix;
        let plugin = null;
 
        if (pluginName.match(/\s+/)) {
            const whitespaceError = new Error(`Whitespace found in plugin name '${pluginName}'`);
 
            whitespaceError.messageTemplate = "whitespace-found";
            whitespaceError.messageData = {
                pluginName: longName
            };
            throw whitespaceError;
        }
 
        if (!plugins[shortName]) {
            try {
                plugin = require(longName);
            } catch (pluginLoadErr) {
                try {
 
                    // Check whether the plugin exists
                    require.resolve(longName);
                } catch (missingPluginErr) {
 
                    // If the plugin can't be resolved, display the missing plugin error (usually a config or install error)
                    debug(`Failed to load plugin ${longName}.`);
                    missingPluginErr.message = `Failed to load plugin ${pluginName}: ${missingPluginErr.message}`;
                    missingPluginErr.messageTemplate = "plugin-missing";
                    missingPluginErr.messageData = {
                        pluginName: longName
                    };
                    throw missingPluginErr;
                }
 
                // Otherwise, the plugin exists and is throwing on module load for some reason, so print the stack trace.
                throw pluginLoadErr;
            }
 
            this.define(pluginName, plugin);
        }
    },
 
    /**
     * Loads all plugins from an array.
     * @param {string[]} pluginNames An array of plugins names.
     * @returns {void}
     * @throws {Error} If a plugin cannot be loaded.
     */
    loadAll(pluginNames) {
        pluginNames.forEach(this.load, this);
    },
 
    /**
     * Resets plugin information. Use for tests only.
     * @returns {void}
     */
    testReset() {
        plugins = Object.create(null);
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/

Statements: 16.14% (1313 / 8136)      Branches: 0.1% (7 / 7193)      Functions: 0.19% (3 / 1565)      Lines: 16.25% (1313 / 8078)      Ignored: 9 statements, 6 branches     

All files » node-npmtest-eslint/node_modules/eslint/lib/rules/
File Statements Branches Functions Lines
accessor-pairs.js 12.82% (5 / 39) 0% (0 / 44) 0% (0 / 6) 12.82% (5 / 39)
array-bracket-spacing.js 24.39% (10 / 41) 0% (0 / 52) 0% (0 / 13) 24.39% (10 / 41)
array-callback-return.js 26.19% (11 / 42) 0% (0 / 40) 0% (0 / 9) 26.19% (11 / 42)
arrow-body-style.js 7.14% (3 / 42) 0% (0 / 42) 0% (0 / 4) 7.14% (3 / 42)
arrow-parens.js 8.33% (3 / 36) 0% (0 / 34) 0% (0 / 6) 8.33% (3 / 36)
arrow-spacing.js 16.13% (5 / 31) 0% (0 / 14) 0% (0 / 8) 16.13% (5 / 31)
block-scoped-var.js 28.57% (6 / 21) 0% (0 / 4) 0% (0 / 7) 28.57% (6 / 21)
block-spacing.js 16.13% (5 / 31) 0% (0 / 27) 0% (0 / 6) 16.13% (5 / 31)
brace-style.js 11.11% (5 / 45) 0% (0 / 47) 0% (0 / 9) 11.36% (5 / 44)
callback-return.js 10.64% (5 / 47) 0% (0 / 51) 0% (0 / 6) 10.64% (5 / 47)
camelcase.js 8.82% (3 / 34) 0% (0 / 55) 0% (0 / 4) 8.82% (3 / 34)
capitalized-comments.js 20.34% (12 / 59) 0% (0 / 48) 0% (0 / 10) 20.34% (12 / 59)
class-methods-use-this.js 33.33% (6 / 18) 0% (0 / 15) 0% (0 / 6) 33.33% (6 / 18)
comma-dangle.js 19.7% (13 / 66) 0% (0 / 60) 0% (0 / 12) 19.7% (13 / 66)
comma-spacing.js 10.87% (5 / 46) 0% (0 / 43) 0% (0 / 6) 10.87% (5 / 46)
comma-style.js 7.89% (6 / 76) 0% (0 / 72) 0% (0 / 16) 7.89% (6 / 76)
complexity.js 27.59% (8 / 29) 0% (0 / 20) 0% (0 / 6) 27.59% (8 / 29)
computed-property-spacing.js 20% (7 / 35) 0% (0 / 22) 0% (0 / 11) 20% (7 / 35)
consistent-return.js 17.07% (7 / 41) 0% (0 / 41) 0% (0 / 8) 17.07% (7 / 41)
consistent-this.js 13.16% (5 / 38) 0% (0 / 31) 0% (0 / 7) 13.89% (5 / 36)
constructor-super.js 6.38% (6 / 94) 0% (0 / 85) 0% (0 / 13) 6.38% (6 / 94)
curly.js 12.04% (13 / 108) 0% (0 / 89) 0% (0 / 19) 12.04% (13 / 108)
default-case.js 15% (3 / 20) 0% (0 / 14) 0% (0 / 3) 15.79% (3 / 19)
dot-location.js 19.05% (4 / 21) 0% (0 / 14) 0% (0 / 3) 19.05% (4 / 21)
dot-notation.js 14.81% (4 / 27) 0% (0 / 28) 0% (0 / 4) 14.81% (4 / 27)
eol-last.js 11.76% (2 / 17) 0% (0 / 16) 0% (0 / 4) 11.76% (2 / 17)
eqeqeq.js 21.62% (8 / 37) 0% (0 / 39) 0% (0 / 9) 21.62% (8 / 37)
func-call-spacing.js 10.71% (3 / 28) 0% (0 / 26) 0% (0 / 5) 10.71% (3 / 28)
func-name-matching.js 19.61% (10 / 51) 0% (0 / 79) 0% (0 / 9) 19.61% (10 / 51)
func-names.js 21.74% (5 / 23) 0% (0 / 36) 0% (0 / 5) 21.74% (5 / 23)
func-style.js 4.76% (1 / 21) 0% (0 / 19) 0% (0 / 8) 4.76% (1 / 21)
generator-star-spacing.js 14.71% (5 / 34) 0% (0 / 28) 0% (0 / 7) 14.71% (5 / 34)
global-require.js 22.22% (4 / 18) 7.69% (1 / 13) 0% (0 / 4) 25% (4 / 16)
guard-for-in.js 20% (1 / 5) 0% (0 / 6) 0% (0 / 2) 20% (1 / 5)
handle-callback-err.js 26.32% (5 / 19) 0% (0 / 12) 0% (0 / 5) 27.78% (5 / 18)
id-blacklist.js 18.18% (4 / 22) 0% (0 / 27) 0% (0 / 5) 18.18% (4 / 22)
id-length.js 4.35% (1 / 23) 0% (0 / 32) 0% (0 / 6) 4.35% (1 / 23)
id-match.js 13.33% (4 / 30) 0% (0 / 43) 0% (0 / 5) 13.33% (4 / 30)
indent.js 8.18% (27 / 330) 0.29% (1 / 350) 0% (0 / 38) 8.31% (27 / 325)
init-declarations.js 12.5% (3 / 24) 0% (0 / 25) 0% (0 / 4) 12.5% (3 / 24)
jsx-quotes.js 30.77% (4 / 13) 0% (0 / 9) 0% (0 / 6) 30.77% (4 / 13)
key-spacing.js 15.67% (21 / 134) 0% (0 / 99) 0% (0 / 24) 15.67% (21 / 134)
keyword-spacing.js 31.01% (40 / 129) 0.94% (1 / 106) 3.33% (1 / 30) 31.01% (40 / 129)
line-comment-position.js 7.41% (2 / 27) 0% (0 / 25) 0% (0 / 2) 7.41% (2 / 27)
linebreak-style.js 16.67% (3 / 18) 0% (0 / 8) 0% (0 / 4) 16.67% (3 / 18)
lines-around-comment.js 16% (16 / 100) 0% (0 / 111) 0% (0 / 19) 16.33% (16 / 98)
lines-around-directive.js 15.22% (7 / 46) 0% (0 / 56) 0% (0 / 7) 15.22% (7 / 46)
max-depth.js 22.73% (5 / 22) 0% (0 / 16) 0% (0 / 6) 22.73% (5 / 22)
max-len.js 17.11% (13 / 76) 0% (0 / 80) 0% (0 / 11) 17.81% (13 / 73)
max-lines.js 11.11% (5 / 45) 0% (0 / 30) 0% (0 / 4) 12.2% (5 / 41)
max-nested-callbacks.js 15% (3 / 20) 0% (0 / 16) 0% (0 / 3) 15% (3 / 20)
max-params.js 26.67% (4 / 15) 0% (0 / 14) 0% (0 / 2) 26.67% (4 / 15)
max-statements-per-line.js 20.69% (6 / 29) 0% (0 / 20) 0% (0 / 5) 20.69% (6 / 29)
max-statements.js 22.58% (7 / 31) 0% (0 / 23) 0% (0 / 6) 22.58% (7 / 31)
multiline-ternary.js 17.65% (3 / 17) 0% (0 / 14) 0% (0 / 3) 17.65% (3 / 17)
new-cap.js 13.51% (10 / 74) 1.61% (1 / 62) 0% (0 / 10) 13.51% (10 / 74)
new-parens.js 16.67% (2 / 12) 0% (0 / 8) 0% (0 / 2) 16.67% (2 / 12)
newline-after-var.js 18.87% (10 / 53) 0% (0 / 52) 0% (0 / 11) 18.87% (10 / 53)
newline-before-return.js 11.67% (7 / 60) 0% (0 / 34) 0% (0 / 9) 11.86% (7 / 59)
newline-per-chained-call.js 15% (3 / 20) 0% (0 / 20) 0% (0 / 3) 15% (3 / 20)
no-alert.js 21.21% (7 / 33) 0% (0 / 25) 0% (0 / 8) 21.88% (7 / 32)
no-array-constructor.js 40% (2 / 5) 0% (0 / 5) 0% (0 / 2) 40% (2 / 5)
no-await-in-loop.js 20% (3 / 15) 0% (0 / 9) 0% (0 / 2) 20% (3 / 15)
no-bitwise.js 41.18% (7 / 17) 0% (0 / 14) 0% (0 / 6) 41.18% (7 / 17)
no-caller.js 20% (1 / 5) 0% (0 / 6) 0% (0 / 2) 20% (1 / 5)
no-case-declarations.js 18.18% (2 / 11) 0% (0 / 6) 0% (0 / 3) 18.18% (2 / 11)
no-catch-shadow.js 30% (3 / 10) 0% (0 / 4) 0% (0 / 3) 30% (3 / 10)
no-class-assign.js 50% (4 / 8) 100% (0 / 0) 0% (0 / 3) 50% (4 / 8)
no-compare-neg-zero.js 25% (2 / 8) 0% (0 / 10) 0% (0 / 3) 25% (2 / 8)
no-cond-assign.js 30.77% (8 / 26) 0% (0 / 27) 0% (0 / 6) 30.77% (8 / 26)
no-confusing-arrow.js 36.36% (4 / 11) 0% (0 / 10) 0% (0 / 3) 36.36% (4 / 11)
no-console.js 25% (6 / 24) 0% (0 / 17) 0% (0 / 6) 25% (6 / 24)
no-const-assign.js 37.5% (3 / 8) 0% (0 / 2) 0% (0 / 3) 37.5% (3 / 8)
no-constant-condition.js 16.67% (5 / 30) 0% (0 / 47) 0% (0 / 5) 16.67% (5 / 30)
no-continue.js 33.33% (1 / 3) 100% (0 / 0) 0% (0 / 2) 33.33% (1 / 3)
no-control-regex.js 8.11% (3 / 37) 0% (0 / 24) 0% (0 / 4) 8.11% (3 / 37)
no-debugger.js 33.33% (1 / 3) 100% (0 / 0) 0% (0 / 2) 33.33% (1 / 3)
no-delete-var.js 25% (1 / 4) 0% (0 / 4) 0% (0 / 2) 25% (1 / 4)
no-div-regex.js 16.67% (1 / 6) 0% (0 / 4) 0% (0 / 2) 16.67% (1 / 6)
no-dupe-args.js 27.27% (3 / 11) 0% (0 / 2) 0% (0 / 3) 27.27% (3 / 11)
no-dupe-class-members.js 12.5% (4 / 32) 4.55% (1 / 22) 0% (0 / 7) 12.5% (4 / 32)
no-dupe-keys.js 13.33% (4 / 30) 0% (0 / 16) 0% (0 / 8) 13.33% (4 / 30)
no-duplicate-case.js 11.11% (1 / 9) 0% (0 / 2) 0% (0 / 2) 11.11% (1 / 9)
no-duplicate-imports.js 17.24% (5 / 29) 0% (0 / 17) 0% (0 / 7) 17.24% (5 / 29)
no-else-return.js 18.33% (11 / 60) 0% (0 / 46) 0% (0 / 9) 18.33% (11 / 60)
no-empty-character-class.js 28.57% (2 / 7) 0% (0 / 4) 0% (0 / 2) 28.57% (2 / 7)
no-empty-function.js 12.82% (5 / 39) 0% (0 / 32) 0% (0 / 3) 12.82% (5 / 39)
no-empty-pattern.js 16.67% (1 / 6) 0% (0 / 4) 0% (0 / 3) 16.67% (1 / 6)
no-empty.js 12.5% (2 / 16) 0% (0 / 18) 0% (0 / 3) 12.5% (2 / 16)
no-eq-null.js 20% (1 / 5) 0% (0 / 10) 0% (0 / 2) 20% (1 / 5)
no-eval.js 14.86% (11 / 74) 0% (0 / 49) 0% (0 / 14) 14.86% (11 / 74)
no-ex-assign.js 42.86% (3 / 7) 100% (0 / 0) 0% (0 / 3) 42.86% (3 / 7)
no-extend-native.js 8% (2 / 25) 0% (0 / 32) 0% (0 / 3) 8.7% (2 / 23)
no-extra-bind.js 33.33% (8 / 24) 0% (0 / 15) 0% (0 / 8) 33.33% (8 / 24)
no-extra-boolean-cast.js 11.54% (3 / 26) 0% (0 / 30) 0% (0 / 4) 11.54% (3 / 26)
no-extra-label.js 28% (7 / 25) 0% (0 / 18) 0% (0 / 6) 28% (7 / 25)
no-extra-parens.js 10.55% (21 / 199) 0% (0 / 289) 0% (0 / 40) 10.55% (21 / 199)
no-extra-semi.js 29.41% (5 / 17) 0% (0 / 6) 0% (0 / 7) 29.41% (5 / 17)
no-fallthrough.js 21.43% (6 / 28) 0% (0 / 18) 0% (0 / 8) 21.43% (6 / 28)
no-floating-decimal.js 11.11% (1 / 9) 0% (0 / 6) 0% (0 / 2) 11.11% (1 / 9)
no-func-assign.js 45.45% (5 / 11) 0% (0 / 2) 0% (0 / 4) 45.45% (5 / 11)
no-global-assign.js 23.08% (3 / 13) 0% (0 / 13) 0% (0 / 4) 23.08% (3 / 13)
no-implicit-coercion.js 22.54% (16 / 71) 0% (0 / 93) 0% (0 / 16) 22.54% (16 / 71)
no-implicit-globals.js 6.67% (1 / 15) 0% (0 / 11) 0% (0 / 2) 6.67% (1 / 15)
no-implied-eval.js 20.69% (6 / 29) 0% (0 / 29) 0% (0 / 12) 20.69% (6 / 29)
no-inline-comments.js 25% (3 / 12) 0% (0 / 5) 0% (0 / 2) 25% (3 / 12)
no-inner-declarations.js 20% (3 / 15) 0% (0 / 15) 0% (0 / 4) 20% (3 / 15)
no-invalid-regexp.js 19.05% (4 / 21) 0% (0 / 18) 0% (0 / 3) 19.05% (4 / 21)
no-invalid-this.js 20% (4 / 20) 0% (0 / 12) 0% (0 / 7) 20% (4 / 20)
no-irregular-whitespace.js 19.44% (14 / 72) 0% (0 / 39) 0% (0 / 11) 19.44% (14 / 72)
no-iterator.js 25% (1 / 4) 0% (0 / 8) 0% (0 / 2) 25% (1 / 4)
no-label-var.js 37.5% (3 / 8) 0% (0 / 2) 0% (0 / 3) 37.5% (3 / 8)
no-labels.js 18.18% (6 / 33) 0% (0 / 23) 0% (0 / 8) 18.18% (6 / 33)
no-lone-blocks.js 12.5% (4 / 32) 0% (0 / 28) 0% (0 / 9) 12.5% (4 / 32)
no-lonely-if.js 5.88% (1 / 17) 0% (0 / 23) 0% (0 / 3) 5.88% (1 / 17)
no-loop-func.js 13.04% (6 / 46) 0% (0 / 45) 0% (0 / 6) 13.04% (6 / 46)
no-magic-numbers.js 20.69% (6 / 29) 0% (0 / 37) 0% (0 / 7) 20.69% (6 / 29)
no-mixed-operators.js 42.5% (17 / 40) 0% (0 / 23) 0% (0 / 8) 43.59% (17 / 39)
no-mixed-requires.js 11.54% (6 / 52) 0% (0 / 39) 0% (0 / 7) 11.54% (6 / 52)
no-mixed-spaces-and-tabs.js 7.32% (3 / 41) 0% (0 / 23) 0% (0 / 5) 7.32% (3 / 41)
no-multi-assign.js 25% (1 / 4) 0% (0 / 2) 0% (0 / 2) 25% (1 / 4)
no-multi-spaces.js 11.76% (4 / 34) 0% (0 / 22) 0% (0 / 5) 11.76% (4 / 34)
no-multi-str.js 42.86% (3 / 7) 0% (0 / 4) 0% (0 / 3) 42.86% (3 / 7)
no-multiple-empty-lines.js 3.33% (1 / 30) 0% (0 / 20) 0% (0 / 4) 3.33% (1 / 30)
no-native-reassign.js 23.08% (3 / 13) 0% (0 / 13) 0% (0 / 4) 23.08% (3 / 13)
no-negated-condition.js 31.25% (5 / 16) 0% (0 / 15) 0% (0 / 7) 31.25% (5 / 16)
no-negated-in-lhs.js 25% (1 / 4) 0% (0 / 5) 0% (0 / 2) 25% (1 / 4)
no-nested-ternary.js 25% (1 / 4) 0% (0 / 4) 0% (0 / 2) 25% (1 / 4)
no-new-func.js 50% (2 / 4) 100% (0 / 0) 0% (0 / 2) 50% (2 / 4)
no-new-object.js 25% (1 / 4) 0% (0 / 2) 0% (0 / 2) 25% (1 / 4)
no-new-require.js 25% (1 / 4) 0% (0 / 4) 0% (0 / 2) 25% (1 / 4)
no-new-symbol.js 11.11% (1 / 9) 0% (0 / 8) 0% (0 / 2) 11.11% (1 / 9)
no-new-wrappers.js 20% (1 / 5) 0% (0 / 2) 0% (0 / 2) 20% (1 / 5)
no-new.js 33.33% (1 / 3) 100% (0 / 0) 0% (0 / 2) 33.33% (1 / 3)
no-obj-calls.js 16.67% (1 / 6) 0% (0 / 7) 0% (0 / 2) 16.67% (1 / 6)
no-octal-escape.js 11.11% (1 / 9) 0% (0 / 8) 0% (0 / 2) 11.11% (1 / 9)
no-octal.js 25% (1 / 4) 0% (0 / 4) 0% (0 / 2) 25% (1 / 4)
no-param-reassign.js 15.38% (6 / 39) 0% (0 / 36) 0% (0 / 5) 15.38% (6 / 39)
no-path-concat.js 16.67% (1 / 6) 0% (0 / 7) 0% (0 / 2) 16.67% (1 / 6)
no-plusplus.js 11.11% (1 / 9) 0% (0 / 6) 0% (0 / 2) 11.11% (1 / 9)
no-process-env.js 20% (1 / 5) 0% (0 / 6) 0% (0 / 2) 20% (1 / 5)
no-process-exit.js 33.33% (1 / 3) 100% (0 / 0) 0% (0 / 2) 33.33% (1 / 3)
no-proto.js 25% (1 / 4) 0% (0 / 8) 0% (0 / 2) 25% (1 / 4)
no-prototype-builtins.js 22.22% (2 / 9) 0% (0 / 6) 0% (0 / 2) 22.22% (2 / 9)
no-redeclare.js 19.05% (4 / 21) 0% (0 / 16) 0% (0 / 4) 20% (4 / 20)
no-regex-spaces.js 27.27% (6 / 22) 0% (0 / 15) 0% (0 / 6) 27.27% (6 / 22)
no-restricted-globals.js 18.75% (3 / 16) 0% (0 / 8) 0% (0 / 4) 18.75% (3 / 16)
no-restricted-imports.js 17.65% (3 / 17) 0% (0 / 25) 0% (0 / 2) 17.65% (3 / 17)
no-restricted-modules.js 22.73% (5 / 22) 0% (0 / 31) 0% (0 / 4) 22.73% (5 / 22)
no-restricted-properties.js 9.3% (4 / 43) 0% (0 / 32) 0% (0 / 5) 9.3% (4 / 43)
no-restricted-syntax.js 12.5% (1 / 8) 0% (0 / 8) 0% (0 / 2) 12.5% (1 / 8)
no-return-assign.js 18.75% (3 / 16) 0% (0 / 17) 0% (0 / 2) 18.75% (3 / 16)
no-return-await.js 22.22% (6 / 27) 0% (0 / 29) 0% (0 / 5) 22.22% (6 / 27)
no-script-url.js 16.67% (1 / 6) 0% (0 / 6) 0% (0 / 2) 16.67% (1 / 6)
no-self-assign.js 13.21% (7 / 53) 0% (0 / 63) 0% (0 / 6) 13.21% (7 / 53)
no-self-compare.js 20% (1 / 5) 0% (0 / 9) 0% (0 / 2) 20% (1 / 5)
no-sequences.js 23.81% (5 / 21) 0% (0 / 21) 0% (0 / 5) 23.81% (5 / 21)
no-shadow-restricted-names.js 13.33% (2 / 15) 0% (0 / 6) 0% (0 / 7) 13.33% (2 / 15)
no-shadow.js 20% (8 / 40) 0% (0 / 46) 0% (0 / 8) 20% (8 / 40)
no-spaced-func.js 16.67% (2 / 12) 0% (0 / 8) 0% (0 / 3) 16.67% (2 / 12)
no-sparse-arrays.js 20% (1 / 5) 0% (0 / 2) 0% (0 / 2) 20% (1 / 5)
no-sync.js 33.33% (1 / 3) 100% (0 / 0) 0% (0 / 2) 33.33% (1 / 3)
no-tabs.js 28.57% (2 / 7) 0% (0 / 2) 0% (0 / 2) 28.57% (2 / 7)
no-template-curly-in-string.js 20% (1 / 5) 0% (0 / 4) 0% (0 / 2) 20% (1 / 5)
no-ternary.js 33.33% (1 / 3) 100% (0 / 0) 0% (0 / 2) 33.33% (1 / 3)
no-this-before-super.js 13.33% (8 / 60) 0% (0 / 46) 0% (0 / 15) 13.33% (8 / 60)
no-throw-literal.js 25% (2 / 8) 0% (0 / 6) 0% (0 / 2) 25% (2 / 8)
no-trailing-spaces.js 10.34% (3 / 29) 0% (0 / 20) 0% (0 / 4) 10.34% (3 / 29)
no-undef-init.js 20% (2 / 10) 0% (0 / 13) 0% (0 / 3) 20% (2 / 10)
no-undef.js 15.38% (2 / 13) 0% (0 / 9) 0% (0 / 3) 15.38% (2 / 13)
no-undefined.js 14.29% (3 / 21) 0% (0 / 2) 0% (0 / 4) 15% (3 / 20)
no-underscore-dangle.js 27.59% (8 / 29) 0% (0 / 36) 0% (0 / 8) 28.57% (8 / 28)
no-unexpected-multiline.js 14.29% (3 / 21) 0% (0 / 8) 0% (0 / 5) 14.29% (3 / 21)
no-unmodified-loop-condition.js 20.79% (21 / 101) 0% (0 / 54) 0% (0 / 16) 20.79% (21 / 101)
no-unneeded-ternary.js 25% (8 / 32) 0% (0 / 33) 0% (0 / 7) 25% (8 / 32)
no-unreachable.js 10.81% (4 / 37) 0% (0 / 20) 0% (0 / 15) 10.81% (4 / 37)
no-unsafe-finally.js 25.93% (7 / 27) 0% (0 / 23) 0% (0 / 4) 25.93% (7 / 27)
no-unsafe-negation.js 28.57% (4 / 14) 0% (0 / 9) 0% (0 / 5) 28.57% (4 / 14)
no-unused-expressions.js 22.22% (6 / 27) 0% (0 / 38) 0% (0 / 7) 22.22% (6 / 27)
no-unused-labels.js 17.39% (4 / 23) 0% (0 / 8) 0% (0 / 5) 17.39% (4 / 23)
no-unused-vars.js 10.34% (18 / 174) 0% (0 / 155) 0% (0 / 17) 10.53% (18 / 171)
no-use-before-define.js 16.9% (12 / 71) 0% (0 / 53) 0% (0 / 12) 16.9% (12 / 71)
no-useless-call.js 19.23% (5 / 26) 0% (0 / 22) 0% (0 / 5) 19.23% (5 / 26)
no-useless-computed-key.js 19.05% (4 / 21) 0% (0 / 15) 0% (0 / 3) 20% (4 / 20)
no-useless-concat.js 24% (6 / 25) 0% (0 / 11) 0% (0 / 6) 24% (6 / 25)
no-useless-constructor.js 32.26% (10 / 31) 0% (0 / 32) 0% (0 / 10) 32.26% (10 / 31)
no-useless-escape.js 21.31% (13 / 61) 0% (0 / 53) 28.57% (2 / 7) 21.31% (13 / 61)
no-useless-rename.js 17.86% (5 / 28) 0% (0 / 30) 0% (0 / 6) 17.86% (5 / 28)
no-useless-return.js 15.63% (10 / 64) 0% (0 / 30) 0% (0 / 13) 15.63% (10 / 64)
no-var.js 22.22% (16 / 72) 0% (0 / 49) 0% (0 / 16) 22.54% (16 / 71)
no-void.js 25% (1 / 4) 0% (0 / 2) 0% (0 / 2) 25% (1 / 4)
no-warning-comments.js 18.52% (5 / 27) 0% (0 / 18) 0% (0 / 4) 18.52% (5 / 27)
no-whitespace-before-property.js 14.29% (3 / 21) 0% (0 / 12) 0% (0 / 4) 14.29% (3 / 21)
no-with.js 33.33% (1 / 3) 100% (0 / 0) 0% (0 / 2) 33.33% (1 / 3)
nonblock-statement-body-position.js 14.81% (4 / 27) 0% (0 / 23) 0% (0 / 5) 14.81% (4 / 27)
object-curly-newline.js 13.33% (6 / 45) 0% (0 / 27) 0% (0 / 8) 13.33% (6 / 45)
object-curly-spacing.js 19.67% (12 / 61) 0% (0 / 45) 0% (0 / 15) 19.67% (12 / 61)
object-property-newline.js 4.76% (1 / 21) 0% (0 / 14) 0% (0 / 3) 4.76% (1 / 21)
object-shorthand.js 10.69% (14 / 131) 0% (0 / 127) 0% (0 / 20) 11.38% (14 / 123)
one-var-declaration-per-line.js 17.65% (3 / 17) 0% (0 / 14) 0% (0 / 3) 17.65% (3 / 17)
one-var.js 8.18% (9 / 110) 0% (0 / 109) 0% (0 / 10) 8.18% (9 / 110)
operator-assignment.js 17.31% (9 / 52) 0% (0 / 39) 0% (0 / 10) 17.65% (9 / 51)
operator-linebreak.js 8.77% (5 / 57) 0% (0 / 63) 0% (0 / 6) 8.77% (5 / 57)
padded-blocks.js 12.68% (9 / 71) 2.27% (1 / 44) 0% (0 / 15) 12.68% (9 / 71)
prefer-arrow-callback.js 12.82% (10 / 78) 0% (0 / 72) 0% (0 / 14) 13.16% (10 / 76)
prefer-const.js 13.48% (12 / 89) 0% (0 / 66) 0% (0 / 10) 13.64% (12 / 88)
prefer-destructuring.js 14.63% (6 / 41) 0% (0 / 34) 0% (0 / 6) 14.63% (6 / 41)
prefer-numeric-literals.js 7.69% (1 / 13) 0% (0 / 10) 0% (0 / 3) 7.69% (1 / 13)
prefer-promise-reject-errors.js 21.05% (4 / 19) 0% (0 / 29) 0% (0 / 5) 21.05% (4 / 19)
prefer-reflect.js 11.11% (2 / 18) 0% (0 / 18) 0% (0 / 4) 11.11% (2 / 18)
prefer-rest-params.js 31.58% (6 / 19) 0% (0 / 9) 0% (0 / 5) 31.58% (6 / 19)
prefer-spread.js 16.13% (5 / 31) 0% (0 / 25) 0% (0 / 6) 16.67% (5 / 30)
prefer-template.js 16.18% (11 / 68) 0% (0 / 57) 0% (0 / 12) 16.67% (11 / 66)
quote-props.js 10.84% (9 / 83) 0% (0 / 107) 0% (0 / 10) 10.84% (9 / 83)
quotes.js 16.13% (10 / 62) 0% (0 / 75) 0% (0 / 10) 16.13% (10 / 62)
radix.js 20% (8 / 40) 0% (0 / 33) 0% (0 / 7) 20% (8 / 40)
require-await.js 35.71% (5 / 14) 0% (0 / 5) 0% (0 / 5) 35.71% (5 / 14)
require-jsdoc.js 16.67% (4 / 24) 0% (0 / 19) 0% (0 / 8) 16.67% (4 / 24)
require-yield.js 21.43% (3 / 14) 10% (1 / 10) 0% (0 / 4) 21.43% (3 / 14)
rest-spread-spacing.js 9.09% (2 / 22) 0% (0 / 13) 0% (0 / 4) 9.09% (2 / 22)
semi-spacing.js 17.31% (9 / 52) 0% (0 / 42) 0% (0 / 13) 17.31% (9 / 52)
semi.js 14.55% (8 / 55) 0% (0 / 47) 0% (0 / 10) 14.55% (8 / 55)
sort-imports.js 8.16% (4 / 49) 0% (0 / 47) 0% (0 / 6) 9.09% (4 / 44)
sort-keys.js 12.9% (4 / 31) 0% (0 / 27) 0% (0 / 13) 12.9% (4 / 31)
sort-vars.js 7.14% (1 / 14) 0% (0 / 8) 0% (0 / 2) 7.69% (1 / 13)
space-before-blocks.js 12.5% (5 / 40) 0% (0 / 26) 0% (0 / 6) 12.5% (5 / 40)
space-before-function-paren.js 15.15% (5 / 33) 0% (0 / 37) 0% (0 / 4) 15.15% (5 / 33)
space-in-parens.js 10.59% (9 / 85) 0% (0 / 64) 0% (0 / 13) 10.59% (9 / 85)
space-infix-ops.js 14.29% (6 / 42) 0% (0 / 29) 0% (0 / 7) 14.29% (6 / 42)
space-unary-ops.js 19.18% (14 / 73) 0% (0 / 66) 0% (0 / 20) 19.18% (14 / 73)
spaced-comment.js 13.79% (12 / 87) 0% (0 / 65) 0% (0 / 12) 13.79% (12 / 87)
strict.js 19.18% (14 / 73) 0% (0 / 58) 0% (0 / 15) 19.44% (14 / 72)
symbol-description.js 23.08% (3 / 13) 0% (0 / 8) 0% (0 / 3) 23.08% (3 / 13)
template-curly-spacing.js 24% (6 / 25) 0% (0 / 18) 0% (0 / 6) 24% (6 / 25)
template-tag-spacing.js 10.53% (2 / 19) 0% (0 / 10) 0% (0 / 4) 11.11% (2 / 18)
unicode-bom.js 11.11% (1 / 9) 0% (0 / 10) 0% (0 / 4) 11.11% (1 / 9)
use-isnan.js 25% (1 / 4) 0% (0 / 5) 0% (0 / 2) 25% (1 / 4)
valid-jsdoc.js 9.52% (10 / 105) 0% (0 / 131) 0% (0 / 9) 9.52% (10 / 105)
valid-typeof.js 12.5% (2 / 16) 0% (0 / 25) 0% (0 / 3) 12.5% (2 / 16)
vars-on-top.js 18.42% (7 / 38) 0% (0 / 32) 0% (0 / 8) 18.42% (7 / 38)
wrap-iife.js 12.9% (4 / 31) 0% (0 / 30) 0% (0 / 7) 12.9% (4 / 31)
wrap-regex.js 9.09% (1 / 11) 0% (0 / 8) 0% (0 / 2) 9.09% (1 / 11)
yield-star-spacing.js 10.34% (3 / 29) 0% (0 / 18) 0% (0 / 5) 10.34% (3 / 29)
yoda.js 21.67% (13 / 60) 0% (0 / 67) 0% (0 / 13) 22.03% (13 / 59)
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/accessor-pairs.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/accessor-pairs.js

Statements: 12.82% (5 / 39)      Branches: 0% (0 / 44)      Functions: 0% (0 / 6)      Lines: 12.82% (5 / 39)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158                                  1                       1                                   1                                                 1                                                             1                                                                                                            
/**
 * @fileoverview Rule to flag wrapping non-iife in parens
 * @author Gyandeep Singh
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks whether or not a given node is an `Identifier` node which was named a given name.
 * @param {ASTNode} node - A node to check.
 * @param {string} name - An expected name of the node.
 * @returns {boolean} `true` if the node is an `Identifier` node which was named as expected.
 */
function isIdentifier(node, name) {
    return node.type === "Identifier" && node.name === name;
}
 
/**
 * Checks whether or not a given node is an argument of a specified method call.
 * @param {ASTNode} node - A node to check.
 * @param {number} index - An expected index of the node in arguments.
 * @param {string} object - An expected name of the object of the method.
 * @param {string} property - An expected name of the method.
 * @returns {boolean} `true` if the node is an argument of the specified method call.
 */
function isArgumentOfMethodCall(node, index, object, property) {
    const parent = node.parent;
 
    return (
        parent.type === "CallExpression" &&
        parent.callee.type === "MemberExpression" &&
        parent.callee.computed === false &&
        isIdentifier(parent.callee.object, object) &&
        isIdentifier(parent.callee.property, property) &&
        parent.arguments[index] === node
    );
}
 
/**
 * Checks whether or not a given node is a property descriptor.
 * @param {ASTNode} node - A node to check.
 * @returns {boolean} `true` if the node is a property descriptor.
 */
function isPropertyDescriptor(node) {
 
    // Object.defineProperty(obj, "foo", {set: ...})
    if (isArgumentOfMethodCall(node, 2, "Object", "defineProperty") ||
        isArgumentOfMethodCall(node, 2, "Reflect", "defineProperty")
    ) {
        return true;
    }
 
    /*
     * Object.defineProperties(obj, {foo: {set: ...}})
     * Object.create(proto, {foo: {set: ...}})
     */
    node = node.parent.parent;
 
    return node.type === "ObjectExpression" && (
        isArgumentOfMethodCall(node, 1, "Object", "create") ||
        isArgumentOfMethodCall(node, 1, "Object", "defineProperties")
    );
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce getter and setter pairs in objects",
            category: "Best Practices",
            recommended: false
        },
        schema: [{
            type: "object",
            properties: {
                getWithoutSet: {
                    type: "boolean"
                },
                setWithoutGet: {
                    type: "boolean"
                }
            },
            additionalProperties: false
        }]
    },
    create(context) {
        const config = context.options[0] || {};
        const checkGetWithoutSet = config.getWithoutSet === true;
        const checkSetWithoutGet = config.setWithoutGet !== false;
 
        /**
         * Checks a object expression to see if it has setter and getter both present or none.
         * @param {ASTNode} node The node to check.
         * @returns {void}
         * @private
         */
        function checkLonelySetGet(node) {
            let isSetPresent = false;
            let isGetPresent = false;
            const isDescriptor = isPropertyDescriptor(node);
 
            for (let i = 0, end = node.properties.length; i < end; i++) {
                const property = node.properties[i];
 
                let propToCheck = "";
 
                if (property.kind === "init") {
                    if (isDescriptor && !property.computed) {
                        propToCheck = property.key.name;
                    }
                } else {
                    propToCheck = property.kind;
                }
 
                switch (propToCheck) {
                    case "set":
                        isSetPresent = true;
                        break;
 
                    case "get":
                        isGetPresent = true;
                        break;
 
                    default:
 
                        // Do nothing
                }
 
                if (isSetPresent && isGetPresent) {
                    break;
                }
            }
 
            if (checkSetWithoutGet && isSetPresent && !isGetPresent) {
                context.report({ node, message: "Getter is not present." });
            } else if (checkGetWithoutSet && isGetPresent && !isSetPresent) {
                context.report({ node, message: "Setter is not present." });
            }
        }
 
        return {
            ObjectExpression(node) {
                if (checkSetWithoutGet || checkGetWithoutSet) {
                    checkLonelySetGet(node);
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/array-bracket-spacing.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/array-bracket-spacing.js

Statements: 24.39% (10 / 41)      Branches: 0% (0 / 52)      Functions: 0% (0 / 13)      Lines: 24.39% (10 / 41)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231            1           1                                                                               1                                         1                                           1                                           1                                       1                                     1                 1                 1                                                                                                                
/**
 * @fileoverview Disallows or enforces spaces inside of array brackets.
 * @author Jamund Ferguson
 */
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent spacing inside array brackets",
            category: "Stylistic Issues",
            recommended: false
        },
        fixable: "whitespace",
        schema: [
            {
                enum: ["always", "never"]
            },
            {
                type: "object",
                properties: {
                    singleValue: {
                        type: "boolean"
                    },
                    objectsInArrays: {
                        type: "boolean"
                    },
                    arraysInArrays: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
    create(context) {
        const spaced = context.options[0] === "always",
            sourceCode = context.getSourceCode();
 
        /**
         * Determines whether an option is set, relative to the spacing option.
         * If spaced is "always", then check whether option is set to false.
         * If spaced is "never", then check whether option is set to true.
         * @param {Object} option - The option to exclude.
         * @returns {boolean} Whether or not the property is excluded.
         */
        function isOptionSet(option) {
            return context.options[1] ? context.options[1][option] === !spaced : false;
        }
 
        const options = {
            spaced,
            singleElementException: isOptionSet("singleValue"),
            objectsInArraysException: isOptionSet("objectsInArrays"),
            arraysInArraysException: isOptionSet("arraysInArrays")
        };
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
        * Reports that there shouldn't be a space after the first token
        * @param {ASTNode} node - The node to report in the event of an error.
        * @param {Token} token - The token to use for the report.
        * @returns {void}
        */
        function reportNoBeginningSpace(node, token) {
            context.report({
                node,
                loc: token.loc.start,
                message: "There should be no space after '{{tokenValue}}'.",
                data: {
                    tokenValue: token.value
                },
                fix(fixer) {
                    const nextToken = sourceCode.getTokenAfter(token);
 
                    return fixer.removeRange([token.range[1], nextToken.range[0]]);
                }
            });
        }
 
        /**
        * Reports that there shouldn't be a space before the last token
        * @param {ASTNode} node - The node to report in the event of an error.
        * @param {Token} token - The token to use for the report.
        * @returns {void}
        */
        function reportNoEndingSpace(node, token) {
            context.report({
                node,
                loc: token.loc.start,
                message: "There should be no space before '{{tokenValue}}'.",
                data: {
                    tokenValue: token.value
                },
                fix(fixer) {
                    const previousToken = sourceCode.getTokenBefore(token);
 
                    return fixer.removeRange([previousToken.range[1], token.range[0]]);
                }
            });
        }
 
        /**
        * Reports that there should be a space after the first token
        * @param {ASTNode} node - The node to report in the event of an error.
        * @param {Token} token - The token to use for the report.
        * @returns {void}
        */
        function reportRequiredBeginningSpace(node, token) {
            context.report({
                node,
                loc: token.loc.start,
                message: "A space is required after '{{tokenValue}}'.",
                data: {
                    tokenValue: token.value
                },
                fix(fixer) {
                    return fixer.insertTextAfter(token, " ");
                }
            });
        }
 
        /**
        * Reports that there should be a space before the last token
        * @param {ASTNode} node - The node to report in the event of an error.
        * @param {Token} token - The token to use for the report.
        * @returns {void}
        */
        function reportRequiredEndingSpace(node, token) {
            context.report({
                node,
                loc: token.loc.start,
                message: "A space is required before '{{tokenValue}}'.",
                data: {
                    tokenValue: token.value
                },
                fix(fixer) {
                    return fixer.insertTextBefore(token, " ");
                }
            });
        }
 
        /**
        * Determines if a node is an object type
        * @param {ASTNode} node - The node to check.
        * @returns {boolean} Whether or not the node is an object type.
        */
        function isObjectType(node) {
            return node && (node.type === "ObjectExpression" || node.type === "ObjectPattern");
        }
 
        /**
        * Determines if a node is an array type
        * @param {ASTNode} node - The node to check.
        * @returns {boolean} Whether or not the node is an array type.
        */
        function isArrayType(node) {
            return node && (node.type === "ArrayExpression" || node.type === "ArrayPattern");
        }
 
        /**
         * Validates the spacing around array brackets
         * @param {ASTNode} node - The node we're checking for spacing
         * @returns {void}
         */
        function validateArraySpacing(node) {
            if (options.spaced && node.elements.length === 0) {
                return;
            }
 
            const first = sourceCode.getFirstToken(node),
                second = sourceCode.getFirstToken(node, 1),
                last = node.typeAnnotation
                    ? sourceCode.getTokenBefore(node.typeAnnotation)
                    : sourceCode.getLastToken(node),
                penultimate = sourceCode.getTokenBefore(last),
                firstElement = node.elements[0],
                lastElement = node.elements[node.elements.length - 1];
 
            const openingBracketMustBeSpaced =
                options.objectsInArraysException && isObjectType(firstElement) ||
                options.arraysInArraysException && isArrayType(firstElement) ||
                options.singleElementException && node.elements.length === 1
                    ? !options.spaced : options.spaced;
 
            const closingBracketMustBeSpaced =
                options.objectsInArraysException && isObjectType(lastElement) ||
                options.arraysInArraysException && isArrayType(lastElement) ||
                options.singleElementException && node.elements.length === 1
                    ? !options.spaced : options.spaced;
 
            if (astUtils.isTokenOnSameLine(first, second)) {
                if (openingBracketMustBeSpaced && !sourceCode.isSpaceBetweenTokens(first, second)) {
                    reportRequiredBeginningSpace(node, first);
                }
                if (!openingBracketMustBeSpaced && sourceCode.isSpaceBetweenTokens(first, second)) {
                    reportNoBeginningSpace(node, first);
                }
            }
 
            if (first !== penultimate && astUtils.isTokenOnSameLine(penultimate, last)) {
                if (closingBracketMustBeSpaced && !sourceCode.isSpaceBetweenTokens(penultimate, last)) {
                    reportRequiredEndingSpace(node, last);
                }
                if (!closingBracketMustBeSpaced && sourceCode.isSpaceBetweenTokens(penultimate, last)) {
                    reportNoEndingSpace(node, last);
                }
            }
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            ArrayPattern: validateArraySpacing,
            ArrayExpression: validateArraySpacing
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/array-callback-return.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/array-callback-return.js

Statements: 26.19% (11 / 42)      Branches: 0% (0 / 40)      Functions: 0% (0 / 9)      Lines: 26.19% (11 / 42)      Ignored: 1 statement     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230                      1   1           1 1               1                           1                             1                             1                                                                                                               1             1                                                           1                                                                                                                                
/**
 * @fileoverview Rule to enforce return statements in callbacks of array's methods
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const lodash = require("lodash");
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const TARGET_NODE_TYPE = /^(?:Arrow)?FunctionExpression$/;
const TARGET_METHODS = /^(?:every|filter|find(?:Index)?|map|reduce(?:Right)?|some|sort)$/;
 
/**
 * Checks a given code path segment is reachable.
 *
 * @param {CodePathSegment} segment - A segment to check.
 * @returns {boolean} `true` if the segment is reachable.
 */
function isReachable(segment) {
    return segment.reachable;
}
 
/**
 * Gets a readable location.
 *
 * - FunctionExpression -> the function name or `function` keyword.
 * - ArrowFunctionExpression -> `=>` token.
 *
 * @param {ASTNode} node - A function node to get.
 * @param {SourceCode} sourceCode - A source code to get tokens.
 * @returns {ASTNode|Token} The node or the token of a location.
 */
function getLocation(node, sourceCode) {
    if (node.type === "ArrowFunctionExpression") {
        return sourceCode.getTokenBefore(node.body);
    }
    return node.id || node;
}
 
/**
 * Checks a given node is a MemberExpression node which has the specified name's
 * property.
 *
 * @param {ASTNode} node - A node to check.
 * @returns {boolean} `true` if the node is a MemberExpression node which has
 *      the specified name's property
 */
function isTargetMethod(node) {
    return (
        node.type === "MemberExpression" &&
        TARGET_METHODS.test(astUtils.getStaticPropertyName(node) || "")
    );
}
 
/**
 * Checks whether or not a given node is a function expression which is the
 * callback of an array method.
 *
 * @param {ASTNode} node - A node to check. This is one of
 *      FunctionExpression or ArrowFunctionExpression.
 * @returns {boolean} `true` if the node is the callback of an array method.
 */
function isCallbackOfArrayMethod(node) {
    while (node) {
        const parent = node.parent;
 
        switch (parent.type) {
 
            /*
             * Looks up the destination. e.g.,
             * foo.every(nativeFoo || function foo() { ... });
             */
            case "LogicalExpression":
            case "ConditionalExpression":
                node = parent;
                break;
 
            // If the upper function is IIFE, checks the destination of the return value.
            // e.g.
            //   foo.every((function() {
            //     // setup...
            //     return function callback() { ... };
            //   })());
            case "ReturnStatement": {
                const func = astUtils.getUpperFunction(parent);
 
                if (func === null || !astUtils.isCallee(func)) {
                    return false;
                }
                node = func.parent;
                break;
            }
 
            // e.g.
            //   Array.from([], function() {});
            //   list.every(function() {});
            case "CallExpression":
                if (astUtils.isArrayFromMethod(parent.callee)) {
                    return (
                        parent.arguments.length >= 2 &&
                        parent.arguments[1] === node
                    );
                }
                if (isTargetMethod(parent.callee)) {
                    return (
                        parent.arguments.length >= 1 &&
                        parent.arguments[0] === node
                    );
                }
                return false;
 
            // Otherwise this node is not target.
            default:
                return false;
        }
    }
 
    /* istanbul ignore next: unreachable */
    return false;
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce `return` statements in callbacks of array methods",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
        let funcInfo = {
            upper: null,
            codePath: null,
            hasReturn: false,
            shouldCheck: false,
            node: null
        };
 
        /**
         * Checks whether or not the last code path segment is reachable.
         * Then reports this function if the segment is reachable.
         *
         * If the last code path segment is reachable, there are paths which are not
         * returned or thrown.
         *
         * @param {ASTNode} node - A node to check.
         * @returns {void}
         */
        function checkLastSegment(node) {
            if (funcInfo.shouldCheck &&
                funcInfo.codePath.currentSegments.some(isReachable)
            ) {
                context.report({
                    node,
                    loc: getLocation(node, context.getSourceCode()).loc.start,
                    message: funcInfo.hasReturn
                        ? "Expected to return a value at the end of {{name}}."
                        : "Expected to return a value in {{name}}.",
                    data: {
                        name: astUtils.getFunctionNameWithKind(funcInfo.node)
                    }
                });
            }
        }
 
        return {
 
            // Stacks this function's information.
            onCodePathStart(codePath, node) {
                funcInfo = {
                    upper: funcInfo,
                    codePath,
                    hasReturn: false,
                    shouldCheck:
                        TARGET_NODE_TYPE.test(node.type) &&
                        node.body.type === "BlockStatement" &&
                        isCallbackOfArrayMethod(node) &&
                        !node.async &&
                        !node.generator,
                    node
                };
            },
 
            // Pops this function's information.
            onCodePathEnd() {
                funcInfo = funcInfo.upper;
            },
 
            // Checks the return statement is valid.
            ReturnStatement(node) {
                if (funcInfo.shouldCheck) {
                    funcInfo.hasReturn = true;
 
                    if (!node.argument) {
                        context.report({
                            node,
                            message: "{{name}} expected a return value.",
                            data: {
                                name: lodash.upperFirst(astUtils.getFunctionNameWithKind(funcInfo.node))
                            }
                        });
                    }
                }
            },
 
            // Reports a given function if the last path is reachable.
            "FunctionExpression:exit": checkLastSegment,
            "ArrowFunctionExpression:exit": checkLastSegment
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/arrow-body-style.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/arrow-body-style.js

Statements: 7.14% (3 / 42)      Branches: 0% (0 / 42)      Functions: 0% (0 / 4)      Lines: 7.14% (3 / 42)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164                    1           1                                                                                                               1                                                                                                                                                                                      
/**
 * @fileoverview Rule to require braces in arrow function body.
 * @author Alberto Rodríguez
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require braces around arrow function bodies",
            category: "ECMAScript 6",
            recommended: false
        },
 
        schema: {
            anyOf: [
                {
                    type: "array",
                    items: [
                        {
                            enum: ["always", "never"]
                        }
                    ],
                    minItems: 0,
                    maxItems: 1
                },
                {
                    type: "array",
                    items: [
                        {
                            enum: ["as-needed"]
                        },
                        {
                            type: "object",
                            properties: {
                                requireReturnForObjectLiteral: { type: "boolean" }
                            },
                            additionalProperties: false
                        }
                    ],
                    minItems: 0,
                    maxItems: 2
                }
            ]
        },
 
        fixable: "code"
    },
 
    create(context) {
        const options = context.options;
        const always = options[0] === "always";
        const asNeeded = !options[0] || options[0] === "as-needed";
        const never = options[0] === "never";
        const requireReturnForObjectLiteral = options[1] && options[1].requireReturnForObjectLiteral;
        const sourceCode = context.getSourceCode();
 
        /**
         * Determines whether a arrow function body needs braces
         * @param {ASTNode} node The arrow function node.
         * @returns {void}
         */
        function validate(node) {
            const arrowBody = node.body;
 
            if (arrowBody.type === "BlockStatement") {
                const blockBody = arrowBody.body;
 
                if (blockBody.length !== 1 && !never) {
                    return;
                }
 
                if (asNeeded && requireReturnForObjectLiteral && blockBody[0].type === "ReturnStatement" &&
                    blockBody[0].argument && blockBody[0].argument.type === "ObjectExpression") {
                    return;
                }
 
                if (never || asNeeded && blockBody[0].type === "ReturnStatement") {
                    context.report({
                        node,
                        loc: arrowBody.loc.start,
                        message: "Unexpected block statement surrounding arrow body.",
                        fix(fixer) {
                            if (blockBody.length !== 1 || blockBody[0].type !== "ReturnStatement" || !blockBody[0].argument) {
                                return null;
                            }
 
                            const sourceText = sourceCode.getText();
                            const returnKeyword = sourceCode.getFirstToken(blockBody[0]);
                            const firstValueToken = sourceCode.getTokenAfter(returnKeyword);
                            let lastValueToken = sourceCode.getLastToken(blockBody[0]);
 
                            if (astUtils.isSemicolonToken(lastValueToken)) {
 
                                /* The last token of the returned value is the last token of the ReturnExpression (if
                                 * the ReturnExpression has no semicolon), or the second-to-last token (if the ReturnExpression
                                 * has a semicolon).
                                 */
                                lastValueToken = sourceCode.getTokenBefore(lastValueToken);
                            }
 
                            const tokenAfterArrowBody = sourceCode.getTokenAfter(arrowBody);
 
                            if (tokenAfterArrowBody && tokenAfterArrowBody.type === "Punctuator" && /^[([/`+-]/.test(tokenAfterArrowBody.value)) {
 
                                // Don't do a fix if the next token would cause ASI issues when preceded by the returned value.
                                return null;
                            }
 
                            const textBeforeReturn = sourceText.slice(arrowBody.range[0] + 1, returnKeyword.range[0]);
                            const textBetweenReturnAndValue = sourceText.slice(returnKeyword.range[1], firstValueToken.range[0]);
                            const rawReturnValueText = sourceText.slice(firstValueToken.range[0], lastValueToken.range[1]);
                            const returnValueText = astUtils.isOpeningBraceToken(firstValueToken) ? `(${rawReturnValueText})` : rawReturnValueText;
                            const textAfterValue = sourceText.slice(lastValueToken.range[1], blockBody[0].range[1] - 1);
                            const textAfterReturnStatement = sourceText.slice(blockBody[0].range[1], arrowBody.range[1] - 1);
 
                            /*
                             * For fixes that only contain spaces around the return value, remove the extra spaces.
                             * This avoids ugly fixes that end up with extra spaces after the arrow, e.g. `() =>   0 ;`
                             */
                            return fixer.replaceText(
                                arrowBody,
                                (textBeforeReturn + textBetweenReturnAndValue).replace(/^\s*$/, "") + returnValueText + (textAfterValue + textAfterReturnStatement).replace(/^\s*$/, "")
                            );
                        }
                    });
                }
            } else {
                if (always || (asNeeded && requireReturnForObjectLiteral && arrowBody.type === "ObjectExpression")) {
                    context.report({
                        node,
                        loc: arrowBody.loc.start,
                        message: "Expected block statement surrounding arrow body.",
                        fix(fixer) {
                            const lastTokenBeforeBody = sourceCode.getLastTokenBetween(sourceCode.getFirstToken(node), arrowBody, astUtils.isNotOpeningParenToken);
                            const firstBodyToken = sourceCode.getTokenAfter(lastTokenBeforeBody);
 
                            return fixer.replaceTextRange(
                                [firstBodyToken.range[0], node.range[1]],
                                `{return ${sourceCode.getText().slice(firstBodyToken.range[0], node.range[1])}}`
                            );
                        }
                    });
                }
            }
        }
 
        return {
            ArrowFunctionExpression: validate
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/arrow-parens.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/arrow-parens.js

Statements: 8.33% (3 / 36)      Branches: 0% (0 / 34)      Functions: 0% (0 / 6)      Lines: 8.33% (3 / 36)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152                    1           1                                                                                   1                                                                                                                                                                                          
/**
 * @fileoverview Rule to require parens in arrow function arguments.
 * @author Jxck
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require parentheses around arrow function arguments",
            category: "ECMAScript 6",
            recommended: false
        },
 
        fixable: "code",
 
        schema: [
            {
                enum: ["always", "as-needed"]
            },
            {
                type: "object",
                properties: {
                    requireForBlockBody: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const message = "Expected parentheses around arrow function argument.";
        const asNeededMessage = "Unexpected parentheses around single function argument.";
        const asNeeded = context.options[0] === "as-needed";
        const requireForBlockBodyMessage = "Unexpected parentheses around single function argument having a body with no curly braces";
        const requireForBlockBodyNoParensMessage = "Expected parentheses around arrow function argument having a body with curly braces.";
        const requireForBlockBody = asNeeded && context.options[1] && context.options[1].requireForBlockBody === true;
 
        const sourceCode = context.getSourceCode();
 
 
        /**
         * Determines whether a arrow function argument end with `)`
         * @param {ASTNode} node The arrow function node.
         * @returns {void}
         */
        function parens(node) {
            const token = sourceCode.getFirstToken(node, node.async ? 1 : 0);
 
            // "as-needed", { "requireForBlockBody": true }: x => x
            if (
                requireForBlockBody &&
                node.params.length === 1 &&
                node.params[0].type === "Identifier" &&
                !node.params[0].typeAnnotation &&
                node.body.type !== "BlockStatement" &&
                !node.returnType
            ) {
                if (astUtils.isOpeningParenToken(token)) {
                    context.report({
                        node,
                        message: requireForBlockBodyMessage,
                        fix(fixer) {
                            const paramToken = context.getTokenAfter(token);
                            const closingParenToken = context.getTokenAfter(paramToken);
 
                            return fixer.replaceTextRange([
                                token.range[0],
                                closingParenToken.range[1]
                            ], paramToken.value);
                        }
                    });
                }
                return;
            }
 
            if (
                requireForBlockBody &&
                node.body.type === "BlockStatement"
            ) {
                if (!astUtils.isOpeningParenToken(token)) {
                    context.report({
                        node,
                        message: requireForBlockBodyNoParensMessage,
                        fix(fixer) {
                            return fixer.replaceText(token, `(${token.value})`);
                        }
                    });
                }
                return;
            }
 
            // "as-needed": x => x
            if (asNeeded &&
                node.params.length === 1 &&
                node.params[0].type === "Identifier" &&
                !node.params[0].typeAnnotation &&
                !node.returnType
            ) {
                if (astUtils.isOpeningParenToken(token)) {
                    context.report({
                        node,
                        message: asNeededMessage,
                        fix(fixer) {
                            const paramToken = context.getTokenAfter(token);
                            const closingParenToken = context.getTokenAfter(paramToken);
 
                            return fixer.replaceTextRange([
                                token.range[0],
                                closingParenToken.range[1]
                            ], paramToken.value);
                        }
                    });
                }
                return;
            }
 
            if (token.type === "Identifier") {
                const after = sourceCode.getTokenAfter(token);
 
                // (x) => x
                if (after.value !== ")") {
                    context.report({
                        node,
                        message,
                        fix(fixer) {
                            return fixer.replaceText(token, `(${token.value})`);
                        }
                    });
                }
            }
        }
 
        return {
            ArrowFunctionExpression: parens
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/arrow-spacing.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/arrow-spacing.js

Statements: 16.13% (5 / 31)      Branches: 0% (0 / 14)      Functions: 0% (0 / 8)      Lines: 16.13% (5 / 31)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151                    1           1                                                                                   1                             1                           1                                                                                                                              
/**
 * @fileoverview Rule to define spacing before/after arrow function's arrow.
 * @author Jxck
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent spacing before and after the arrow in arrow functions",
            category: "ECMAScript 6",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                type: "object",
                properties: {
                    before: {
                        type: "boolean"
                    },
                    after: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        // merge rules with default
        const rule = { before: true, after: true },
            option = context.options[0] || {};
 
        rule.before = option.before !== false;
        rule.after = option.after !== false;
 
        const sourceCode = context.getSourceCode();
 
        /**
         * Get tokens of arrow(`=>`) and before/after arrow.
         * @param {ASTNode} node The arrow function node.
         * @returns {Object} Tokens of arrow and before/after arrow.
         */
        function getTokens(node) {
            const arrow = sourceCode.getTokenBefore(node.body, astUtils.isArrowToken);
 
            return {
                before: sourceCode.getTokenBefore(arrow),
                arrow,
                after: sourceCode.getTokenAfter(arrow)
            };
        }
 
        /**
         * Count spaces before/after arrow(`=>`) token.
         * @param {Object} tokens Tokens before/after arrow.
         * @returns {Object} count of space before/after arrow.
         */
        function countSpaces(tokens) {
            const before = tokens.arrow.range[0] - tokens.before.range[1];
            const after = tokens.after.range[0] - tokens.arrow.range[1];
 
            return { before, after };
        }
 
        /**
         * Determines whether space(s) before after arrow(`=>`) is satisfy rule.
         * if before/after value is `true`, there should be space(s).
         * if before/after value is `false`, there should be no space.
         * @param {ASTNode} node The arrow function node.
         * @returns {void}
         */
        function spaces(node) {
            const tokens = getTokens(node);
            const countSpace = countSpaces(tokens);
 
            if (rule.before) {
 
                // should be space(s) before arrow
                if (countSpace.before === 0) {
                    context.report({
                        node: tokens.before,
                        message: "Missing space before =>.",
                        fix(fixer) {
                            return fixer.insertTextBefore(tokens.arrow, " ");
                        }
                    });
                }
            } else {
 
                // should be no space before arrow
                if (countSpace.before > 0) {
                    context.report({
                        node: tokens.before,
                        message: "Unexpected space before =>.",
                        fix(fixer) {
                            return fixer.removeRange([tokens.before.range[1], tokens.arrow.range[0]]);
                        }
                    });
                }
            }
 
            if (rule.after) {
 
                // should be space(s) after arrow
                if (countSpace.after === 0) {
                    context.report({
                        node: tokens.after,
                        message: "Missing space after =>.",
                        fix(fixer) {
                            return fixer.insertTextAfter(tokens.arrow, " ");
                        }
                    });
                }
            } else {
 
                // should be no space after arrow
                if (countSpace.after > 0) {
                    context.report({
                        node: tokens.after,
                        message: "Unexpected space after =>.",
                        fix(fixer) {
                            return fixer.removeRange([tokens.arrow.range[1], tokens.after.range[0]]);
                        }
                    });
                }
            }
        }
 
        return {
            ArrowFunctionExpression: spaces
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/block-scoped-var.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/block-scoped-var.js

Statements: 28.57% (6 / 21)      Branches: 0% (0 / 4)      Functions: 0% (0 / 7)      Lines: 28.57% (6 / 21)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117                    1                                     1               1                 1                     1                           1                                                                                          
/**
 * @fileoverview Rule to check for "block scoped" variables by binding context
 * @author Matt DuVall <http://www.mattduvall.com>
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce the use of variables within the scope they are defined",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
        let stack = [];
 
        /**
         * Makes a block scope.
         * @param {ASTNode} node - A node of a scope.
         * @returns {void}
         */
        function enterScope(node) {
            stack.push(node.range);
        }
 
        /**
         * Pops the last block scope.
         * @returns {void}
         */
        function exitScope() {
            stack.pop();
        }
 
        /**
         * Reports a given reference.
         * @param {escope.Reference} reference - A reference to report.
         * @returns {void}
         */
        function report(reference) {
            const identifier = reference.identifier;
 
            context.report({ node: identifier, message: "'{{name}}' used outside of binding context.", data: { name: identifier.name } });
        }
 
        /**
         * Finds and reports references which are outside of valid scopes.
         * @param {ASTNode} node - A node to get variables.
         * @returns {void}
         */
        function checkForVariables(node) {
            if (node.kind !== "var") {
                return;
            }
 
            // Defines a predicate to check whether or not a given reference is outside of valid scope.
            const scopeRange = stack[stack.length - 1];
 
            /**
             * Check if a reference is out of scope
             * @param {ASTNode} reference node to examine
             * @returns {boolean} True is its outside the scope
             * @private
             */
            function isOutsideOfScope(reference) {
                const idRange = reference.identifier.range;
 
                return idRange[0] < scopeRange[0] || idRange[1] > scopeRange[1];
            }
 
            // Gets declared variables, and checks its references.
            const variables = context.getDeclaredVariables(node);
 
            for (let i = 0; i < variables.length; ++i) {
 
                // Reports.
                variables[i]
                    .references
                    .filter(isOutsideOfScope)
                    .forEach(report);
            }
        }
 
        return {
            Program(node) {
                stack = [node.range];
            },
 
            // Manages scopes.
            BlockStatement: enterScope,
            "BlockStatement:exit": exitScope,
            ForStatement: enterScope,
            "ForStatement:exit": exitScope,
            ForInStatement: enterScope,
            "ForInStatement:exit": exitScope,
            ForOfStatement: enterScope,
            "ForOfStatement:exit": exitScope,
            SwitchStatement: enterScope,
            "SwitchStatement:exit": exitScope,
            CatchClause: enterScope,
            "CatchClause:exit": exitScope,
 
            // Finds and reports references which are outside of valid scope.
            VariableDeclaration: checkForVariables
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/block-spacing.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/block-spacing.js

Statements: 16.13% (5 / 31)      Branches: 0% (0 / 27)      Functions: 0% (0 / 6)      Lines: 16.13% (5 / 31)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139              1           1                                                 1                                         1                       1                                                                                                                                      
/**
 * @fileoverview A rule to disallow or enforce spaces inside of single line blocks.
 * @author Toru Nagashima
 */
 
"use strict";
 
const util = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent spacing inside single-line blocks",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            { enum: ["always", "never"] }
        ]
    },
 
    create(context) {
        const always = (context.options[0] !== "never"),
            message = always ? "Requires a space" : "Unexpected space(s)",
            sourceCode = context.getSourceCode();
 
        /**
         * Gets the open brace token from a given node.
         * @param {ASTNode} node - A BlockStatement/SwitchStatement node to get.
         * @returns {Token} The token of the open brace.
         */
        function getOpenBrace(node) {
            if (node.type === "SwitchStatement") {
                if (node.cases.length > 0) {
                    return sourceCode.getTokenBefore(node.cases[0]);
                }
                return sourceCode.getLastToken(node, 1);
            }
            return sourceCode.getFirstToken(node);
        }
 
        /**
         * Checks whether or not:
         *   - given tokens are on same line.
         *   - there is/isn't a space between given tokens.
         * @param {Token} left - A token to check.
         * @param {Token} right - The token which is next to `left`.
         * @returns {boolean}
         *    When the option is `"always"`, `true` if there are one or more spaces between given tokens.
         *    When the option is `"never"`, `true` if there are not any spaces between given tokens.
         *    If given tokens are not on same line, it's always `true`.
         */
        function isValid(left, right) {
            return (
                !util.isTokenOnSameLine(left, right) ||
                sourceCode.isSpaceBetweenTokens(left, right) === always
            );
        }
 
        /**
         * Reports invalid spacing style inside braces.
         * @param {ASTNode} node - A BlockStatement/SwitchStatement node to get.
         * @returns {void}
         */
        function checkSpacingInsideBraces(node) {
 
            // Gets braces and the first/last token of content.
            const openBrace = getOpenBrace(node);
            const closeBrace = sourceCode.getLastToken(node);
            const firstToken = sourceCode.getTokenAfter(openBrace, { includeComments: true });
            const lastToken = sourceCode.getTokenBefore(closeBrace, { includeComments: true });
 
            // Skip if the node is invalid or empty.
            if (openBrace.type !== "Punctuator" ||
                openBrace.value !== "{" ||
                closeBrace.type !== "Punctuator" ||
                closeBrace.value !== "}" ||
                firstToken === closeBrace
            ) {
                return;
            }
 
            // Skip line comments for option never
            if (!always && firstToken.type === "Line") {
                return;
            }
 
            // Check.
            if (!isValid(openBrace, firstToken)) {
                context.report({
                    node,
                    loc: openBrace.loc.start,
                    message: "{{message}} after '{'.",
                    data: {
                        message
                    },
                    fix(fixer) {
                        if (always) {
                            return fixer.insertTextBefore(firstToken, " ");
                        }
 
                        return fixer.removeRange([openBrace.range[1], firstToken.range[0]]);
                    }
                });
            }
            if (!isValid(lastToken, closeBrace)) {
                context.report({
                    node,
                    loc: closeBrace.loc.start,
                    message: "{{message}} before '}'.",
                    data: {
                        message
                    },
                    fix(fixer) {
                        if (always) {
                            return fixer.insertTextAfter(lastToken, " ");
                        }
 
                        return fixer.removeRange([lastToken.range[1], closeBrace.range[0]]);
                    }
                });
            }
        }
 
        return {
            BlockStatement: checkSpacingInsideBraces,
            SwitchStatement: checkSpacingInsideBraces
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/brace-style.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/brace-style.js

Statements: 11.11% (5 / 45)      Branches: 0% (0 / 47)      Functions: 0% (0 / 9)      Lines: 11.36% (5 / 44)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182              1           1                                                                                               1                             1                                                                                       1                                                                                                                          
/**
 * @fileoverview Rule to flag block statements that do not use the one true brace style
 * @author Ian Christian Myers
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent brace style for blocks",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                enum: ["1tbs", "stroustrup", "allman"]
            },
            {
                type: "object",
                properties: {
                    allowSingleLine: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ],
 
        fixable: "whitespace"
    },
 
    create(context) {
        const style = context.options[0] || "1tbs",
            params = context.options[1] || {},
            sourceCode = context.getSourceCode();
 
        const OPEN_MESSAGE = "Opening curly brace does not appear on the same line as controlling statement.",
            OPEN_MESSAGE_ALLMAN = "Opening curly brace appears on the same line as controlling statement.",
            BODY_MESSAGE = "Statement inside of curly braces should be on next line.",
            CLOSE_MESSAGE = "Closing curly brace does not appear on the same line as the subsequent block.",
            CLOSE_MESSAGE_SINGLE = "Closing curly brace should be on the same line as opening curly brace or on the line after the previous block.",
            CLOSE_MESSAGE_STROUSTRUP_ALLMAN = "Closing curly brace appears on the same line as the subsequent block.";
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
        * Fixes a place where a newline unexpectedly appears
        * @param {Token} firstToken The token before the unexpected newline
        * @param {Token} secondToken The token after the unexpected newline
        * @returns {Function} A fixer function to remove the newlines between the tokens
        */
        function removeNewlineBetween(firstToken, secondToken) {
            const textRange = [firstToken.range[1], secondToken.range[0]];
            const textBetween = sourceCode.text.slice(textRange[0], textRange[1]);
            const NEWLINE_REGEX = astUtils.createGlobalLinebreakMatcher();
 
            // Don't do a fix if there is a comment between the tokens
            return fixer => fixer.replaceTextRange(textRange, textBetween.trim() ? null : textBetween.replace(NEWLINE_REGEX, ""));
        }
 
        /**
        * Validates a pair of curly brackets based on the user's config
        * @param {Token} openingCurly The opening curly bracket
        * @param {Token} closingCurly The closing curly bracket
        * @returns {void}
        */
        function validateCurlyPair(openingCurly, closingCurly) {
            const tokenBeforeOpeningCurly = sourceCode.getTokenBefore(openingCurly);
            const tokenAfterOpeningCurly = sourceCode.getTokenAfter(openingCurly);
            const tokenBeforeClosingCurly = sourceCode.getTokenBefore(closingCurly);
            const singleLineException = params.allowSingleLine && astUtils.isTokenOnSameLine(openingCurly, closingCurly);
 
            if (style !== "allman" && !astUtils.isTokenOnSameLine(tokenBeforeOpeningCurly, openingCurly)) {
                context.report({
                    node: openingCurly,
                    message: OPEN_MESSAGE,
                    fix: removeNewlineBetween(tokenBeforeOpeningCurly, openingCurly)
                });
            }
 
            if (style === "allman" && astUtils.isTokenOnSameLine(tokenBeforeOpeningCurly, openingCurly) && !singleLineException) {
                context.report({
                    node: openingCurly,
                    message: OPEN_MESSAGE_ALLMAN,
                    fix: fixer => fixer.insertTextBefore(openingCurly, "\n")
                });
            }
 
            if (astUtils.isTokenOnSameLine(openingCurly, tokenAfterOpeningCurly) && tokenAfterOpeningCurly !== closingCurly && !singleLineException) {
                context.report({
                    node: openingCurly,
                    message: BODY_MESSAGE,
                    fix: fixer => fixer.insertTextAfter(openingCurly, "\n")
                });
            }
 
            if (tokenBeforeClosingCurly !== openingCurly && !singleLineException && astUtils.isTokenOnSameLine(tokenBeforeClosingCurly, closingCurly)) {
                context.report({
                    node: closingCurly,
                    message: CLOSE_MESSAGE_SINGLE,
                    fix: fixer => fixer.insertTextBefore(closingCurly, "\n")
                });
            }
        }
 
        /**
        * Validates the location of a token that appears before a keyword (e.g. a newline before `else`)
        * @param {Token} curlyToken The closing curly token. This is assumed to precede a keyword token (such as `else` or `finally`).
        * @returns {void}
        */
        function validateCurlyBeforeKeyword(curlyToken) {
            const keywordToken = sourceCode.getTokenAfter(curlyToken);
 
            if (style === "1tbs" && !astUtils.isTokenOnSameLine(curlyToken, keywordToken)) {
                context.report({
                    node: curlyToken,
                    message: CLOSE_MESSAGE,
                    fix: removeNewlineBetween(curlyToken, keywordToken)
                });
            }
 
            if (style !== "1tbs" && astUtils.isTokenOnSameLine(curlyToken, keywordToken)) {
                context.report({
                    node: curlyToken,
                    message: CLOSE_MESSAGE_STROUSTRUP_ALLMAN,
                    fix: fixer => fixer.insertTextAfter(curlyToken, "\n")
                });
            }
        }
 
        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------
 
        return {
            BlockStatement(node) {
                if (!astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type)) {
                    validateCurlyPair(sourceCode.getFirstToken(node), sourceCode.getLastToken(node));
                }
            },
            ClassBody(node) {
                validateCurlyPair(sourceCode.getFirstToken(node), sourceCode.getLastToken(node));
            },
            SwitchStatement(node) {
                const closingCurly = sourceCode.getLastToken(node);
                const openingCurly = sourceCode.getTokenBefore(node.cases.length ? node.cases[0] : closingCurly);
 
                validateCurlyPair(openingCurly, closingCurly);
            },
            IfStatement(node) {
                if (node.consequent.type === "BlockStatement" && node.alternate) {
 
                    // Handle the keyword after the `if` block (before `else`)
                    validateCurlyBeforeKeyword(sourceCode.getLastToken(node.consequent));
                }
            },
            TryStatement(node) {
 
                // Handle the keyword after the `try` block (before `catch` or `finally`)
                validateCurlyBeforeKeyword(sourceCode.getLastToken(node.block));
 
                if (node.handler && node.finalizer) {
 
                    // Handle the keyword after the `catch` block (before `finally`)
                    validateCurlyBeforeKeyword(sourceCode.getLastToken(node.handler.body));
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/callback-return.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/callback-return.js

Statements: 10.64% (5 / 47)      Branches: 0% (0 / 51)      Functions: 0% (0 / 6)      Lines: 10.64% (5 / 47)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176                    1                                                         1                             1                                         1                   1                                                                                                                                                                                    
/**
 * @fileoverview Enforce return after a callback.
 * @author Jamund Ferguson
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require `return` statements after callbacks",
            category: "Node.js and CommonJS",
            recommended: false
        },
 
        schema: [{
            type: "array",
            items: { type: "string" }
        }]
    },
 
    create(context) {
 
        const callbacks = context.options[0] || ["callback", "cb", "next"],
            sourceCode = context.getSourceCode();
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Find the closest parent matching a list of types.
         * @param {ASTNode} node The node whose parents we are searching
         * @param {Array} types The node types to match
         * @returns {ASTNode} The matched node or undefined.
         */
        function findClosestParentOfType(node, types) {
            if (!node.parent) {
                return null;
            }
            if (types.indexOf(node.parent.type) === -1) {
                return findClosestParentOfType(node.parent, types);
            }
            return node.parent;
        }
 
        /**
         * Check to see if a node contains only identifers
         * @param {ASTNode} node The node to check
         * @returns {boolean} Whether or not the node contains only identifers
         */
        function containsOnlyIdentifiers(node) {
            if (node.type === "Identifier") {
                return true;
            }
 
            if (node.type === "MemberExpression") {
                if (node.object.type === "Identifier") {
                    return true;
                } else if (node.object.type === "MemberExpression") {
                    return containsOnlyIdentifiers(node.object);
                }
            }
 
            return false;
        }
 
        /**
         * Check to see if a CallExpression is in our callback list.
         * @param {ASTNode} node The node to check against our callback names list.
         * @returns {boolean} Whether or not this function matches our callback name.
         */
        function isCallback(node) {
            return containsOnlyIdentifiers(node.callee) && callbacks.indexOf(sourceCode.getText(node.callee)) > -1;
        }
 
        /**
         * Determines whether or not the callback is part of a callback expression.
         * @param {ASTNode} node The callback node
         * @param {ASTNode} parentNode The expression node
         * @returns {boolean} Whether or not this is part of a callback expression
         */
        function isCallbackExpression(node, parentNode) {
 
            // ensure the parent node exists and is an expression
            if (!parentNode || parentNode.type !== "ExpressionStatement") {
                return false;
            }
 
            // cb()
            if (parentNode.expression === node) {
                return true;
            }
 
            // special case for cb && cb() and similar
            if (parentNode.expression.type === "BinaryExpression" || parentNode.expression.type === "LogicalExpression") {
                if (parentNode.expression.right === node) {
                    return true;
                }
            }
 
            return false;
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            CallExpression(node) {
 
                // if we're not a callback we can return
                if (!isCallback(node)) {
                    return;
                }
 
                // find the closest block, return or loop
                const closestBlock = findClosestParentOfType(node, ["BlockStatement", "ReturnStatement", "ArrowFunctionExpression"]) || {};
 
                // if our parent is a return we know we're ok
                if (closestBlock.type === "ReturnStatement") {
                    return;
                }
 
                // arrow functions don't always have blocks and implicitly return
                if (closestBlock.type === "ArrowFunctionExpression") {
                    return;
                }
 
                // block statements are part of functions and most if statements
                if (closestBlock.type === "BlockStatement") {
 
                    // find the last item in the block
                    const lastItem = closestBlock.body[closestBlock.body.length - 1];
 
                    // if the callback is the last thing in a block that might be ok
                    if (isCallbackExpression(node, lastItem)) {
 
                        const parentType = closestBlock.parent.type;
 
                        // but only if the block is part of a function
                        if (parentType === "FunctionExpression" ||
                            parentType === "FunctionDeclaration" ||
                            parentType === "ArrowFunctionExpression"
                        ) {
                            return;
                        }
 
                    }
 
                    // ending a block with a return is also ok
                    if (lastItem.type === "ReturnStatement") {
 
                        // but only if the callback is immediately before
                        if (isCallbackExpression(node, closestBlock.body[closestBlock.body.length - 2])) {
                            return;
                        }
                    }
 
                }
 
                // as long as you're the child of a function at this point you should be asked to return
                if (findClosestParentOfType(node, ["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"])) {
                    context.report({ node, message: "Expected return with your callback function." });
                }
 
            }
 
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/camelcase.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/camelcase.js

Statements: 8.82% (3 / 34)      Branches: 0% (0 / 55)      Functions: 0% (0 / 4)      Lines: 8.82% (3 / 34)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145                      1                                                                         1                       1                                                                                                                                                                        
/**
 * @fileoverview Rule to flag non-camelcased identifiers
 * @author Nicholas C. Zakas
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce camelcase naming convention",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    properties: {
                        enum: ["always", "never"]
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        // contains reported nodes to avoid reporting twice on destructuring with shorthand notation
        const reported = [];
        const ALLOWED_PARENT_TYPES = new Set(["CallExpression", "NewExpression"]);
 
        /**
         * Checks if a string contains an underscore and isn't all upper-case
         * @param {string} name The string to check.
         * @returns {boolean} if the string is underscored
         * @private
         */
        function isUnderscored(name) {
 
            // if there's an underscore, it might be A_CONSTANT, which is okay
            return name.indexOf("_") > -1 && name !== name.toUpperCase();
        }
 
        /**
         * Reports an AST node as a rule violation.
         * @param {ASTNode} node The node to report.
         * @returns {void}
         * @private
         */
        function report(node) {
            if (reported.indexOf(node) < 0) {
                reported.push(node);
                context.report({ node, message: "Identifier '{{name}}' is not in camel case.", data: { name: node.name } });
            }
        }
 
        const options = context.options[0] || {};
        let properties = options.properties || "";
 
        if (properties !== "always" && properties !== "never") {
            properties = "always";
        }
 
        return {
 
            Identifier(node) {
 
                /*
                 * Leading and trailing underscores are commonly used to flag
                 * private/protected identifiers, strip them
                 */
                const name = node.name.replace(/^_+|_+$/g, ""),
                    effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent;
 
                // MemberExpressions get special rules
                if (node.parent.type === "MemberExpression") {
 
                    // "never" check properties
                    if (properties === "never") {
                        return;
                    }
 
                    // Always report underscored object names
                    if (node.parent.object.type === "Identifier" &&
                            node.parent.object.name === node.name &&
                            isUnderscored(name)) {
                        report(node);
 
                    // Report AssignmentExpressions only if they are the left side of the assignment
                    } else if (effectiveParent.type === "AssignmentExpression" &&
                            isUnderscored(name) &&
                            (effectiveParent.right.type !== "MemberExpression" ||
                            effectiveParent.left.type === "MemberExpression" &&
                            effectiveParent.left.property.name === node.name)) {
                        report(node);
                    }
 
                // Properties have their own rules
                } else if (node.parent.type === "Property") {
 
                    // "never" check properties
                    if (properties === "never") {
                        return;
                    }
 
                    if (node.parent.parent && node.parent.parent.type === "ObjectPattern" &&
                            node.parent.key === node && node.parent.value !== node) {
                        return;
                    }
 
                    if (isUnderscored(name) && !ALLOWED_PARENT_TYPES.has(effectiveParent.type)) {
                        report(node);
                    }
 
                // Check if it's an import specifier
                } else if (["ImportSpecifier", "ImportNamespaceSpecifier", "ImportDefaultSpecifier"].indexOf(node.parent.type) >= 0) {
 
                    // Report only if the local imported identifier is underscored
                    if (node.parent.local && node.parent.local.name === node.name && isUnderscored(name)) {
                        report(node);
                    }
 
                // Report anything that is underscored that isn't a CallExpression
                } else if (isUnderscored(name) && !ALLOWED_PARENT_TYPES.has(effectiveParent.type)) {
                    report(node);
                }
            }
 
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/capitalized-comments.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/capitalized-comments.js

Statements: 20.34% (12 / 59)      Branches: 0% (0 / 48)      Functions: 0% (0 / 10)      Lines: 20.34% (12 / 59)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304                    1 1           1                               1                                                           1                             1                               1                               1                                                                                                             1                                   1                               1                                                                                                                             1                                                                                  
/**
 * @fileoverview enforce or disallow capitalization of the first letter of a comment
 * @author Kevin Partington
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const LETTER_PATTERN = require("../util/patterns/letters");
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const ALWAYS_MESSAGE = "Comments should not begin with a lowercase character",
    NEVER_MESSAGE = "Comments should not begin with an uppercase character",
    DEFAULT_IGNORE_PATTERN = astUtils.COMMENTS_IGNORE_PATTERN,
    WHITESPACE = /\s/g,
    MAYBE_URL = /^\s*[^:/?#\s]+:\/\/[^?#]/,    // TODO: Combine w/ max-len pattern?
    DEFAULTS = {
        ignorePattern: null,
        ignoreInlineComments: false,
        ignoreConsecutiveComments: false
    };
 
/*
 * Base schema body for defining the basic capitalization rule, ignorePattern,
 * and ignoreInlineComments values.
 * This can be used in a few different ways in the actual schema.
 */
const SCHEMA_BODY = {
    type: "object",
    properties: {
        ignorePattern: {
            type: "string"
        },
        ignoreInlineComments: {
            type: "boolean"
        },
        ignoreConsecutiveComments: {
            type: "boolean"
        }
    },
    additionalProperties: false
};
 
/**
 * Get normalized options for either block or line comments from the given
 * user-provided options.
 * - If the user-provided options is just a string, returns a normalized
 *   set of options using default values for all other options.
 * - If the user-provided options is an object, then a normalized option
 *   set is returned. Options specified in overrides will take priority
 *   over options specified in the main options object, which will in
 *   turn take priority over the rule's defaults.
 *
 * @param {Object|string} rawOptions The user-provided options.
 * @param {string} which Either "line" or "block".
 * @returns {Object} The normalized options.
 */
function getNormalizedOptions(rawOptions, which) {
    if (!rawOptions) {
        return Object.assign({}, DEFAULTS);
    }
 
    return Object.assign({}, DEFAULTS, rawOptions[which] || rawOptions);
}
 
/**
 * Get normalized options for block and line comments.
 *
 * @param {Object|string} rawOptions The user-provided options.
 * @returns {Object} An object with "Line" and "Block" keys and corresponding
 * normalized options objects.
 */
function getAllNormalizedOptions(rawOptions) {
    return {
        Line: getNormalizedOptions(rawOptions, "line"),
        Block: getNormalizedOptions(rawOptions, "block")
    };
}
 
/**
 * Creates a regular expression for each ignorePattern defined in the rule
 * options.
 *
 * This is done in order to avoid invoking the RegExp constructor repeatedly.
 *
 * @param {Object} normalizedOptions The normalized rule options.
 * @returns {void}
 */
function createRegExpForIgnorePatterns(normalizedOptions) {
    Object.keys(normalizedOptions).forEach(key => {
        const ignorePatternStr = normalizedOptions[key].ignorePattern;
 
        if (ignorePatternStr) {
            const regExp = RegExp(`^\\s*(?:${ignorePatternStr})`);
 
            normalizedOptions[key].ignorePatternRegExp = regExp;
        }
    });
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce or disallow capitalization of the first letter of a comment",
            category: "Stylistic Issues",
            recommended: false
        },
        fixable: "code",
        schema: [
            { enum: ["always", "never"] },
            {
                oneOf: [
                    SCHEMA_BODY,
                    {
                        type: "object",
                        properties: {
                            line: SCHEMA_BODY,
                            block: SCHEMA_BODY
                        },
                        additionalProperties: false
                    }
                ]
            }
        ]
    },
 
    create(context) {
 
        const capitalize = context.options[0] || "always",
            normalizedOptions = getAllNormalizedOptions(context.options[1]),
            sourceCode = context.getSourceCode();
 
        createRegExpForIgnorePatterns(normalizedOptions);
 
        //----------------------------------------------------------------------
        // Helpers
        //----------------------------------------------------------------------
 
        /**
         * Checks whether a comment is an inline comment.
         *
         * For the purpose of this rule, a comment is inline if:
         * 1. The comment is preceded by a token on the same line; and
         * 2. The command is followed by a token on the same line.
         *
         * Note that the comment itself need not be single-line!
         *
         * Also, it follows from this definition that only block comments can
         * be considered as possibly inline. This is because line comments
         * would consume any following tokens on the same line as the comment.
         *
         * @param {ASTNode} comment The comment node to check.
         * @returns {boolean} True if the comment is an inline comment, false
         * otherwise.
         */
        function isInlineComment(comment) {
            const previousToken = sourceCode.getTokenBefore(comment, { includeComments: true }),
                nextToken = sourceCode.getTokenAfter(comment, { includeComments: true });
 
            return Boolean(
                previousToken &&
                nextToken &&
                comment.loc.start.line === previousToken.loc.end.line &&
                comment.loc.end.line === nextToken.loc.start.line
            );
        }
 
        /**
         * Determine if a comment follows another comment.
         *
         * @param {ASTNode} comment The comment to check.
         * @returns {boolean} True if the comment follows a valid comment.
         */
        function isConsecutiveComment(comment) {
            const previousTokenOrComment = sourceCode.getTokenBefore(comment, { includeComments: true });
 
            return Boolean(
                previousTokenOrComment &&
                ["Block", "Line"].indexOf(previousTokenOrComment.type) !== -1
            );
        }
 
        /**
         * Check a comment to determine if it is valid for this rule.
         *
         * @param {ASTNode} comment The comment node to process.
         * @param {Object} options The options for checking this comment.
         * @returns {boolean} True if the comment is valid, false otherwise.
         */
        function isCommentValid(comment, options) {
 
            // 1. Check for default ignore pattern.
            if (DEFAULT_IGNORE_PATTERN.test(comment.value)) {
                return true;
            }
 
            // 2. Check for custom ignore pattern.
            const commentWithoutAsterisks = comment.value
                .replace(/\*/g, "");
 
            if (options.ignorePatternRegExp && options.ignorePatternRegExp.test(commentWithoutAsterisks)) {
                return true;
            }
 
            // 3. Check for inline comments.
            if (options.ignoreInlineComments && isInlineComment(comment)) {
                return true;
            }
 
            // 4. Is this a consecutive comment (and are we tolerating those)?
            if (options.ignoreConsecutiveComments && isConsecutiveComment(comment)) {
                return true;
            }
 
            // 5. Does the comment start with a possible URL?
            if (MAYBE_URL.test(commentWithoutAsterisks)) {
                return true;
            }
 
            // 6. Is the initial word character a letter?
            const commentWordCharsOnly = commentWithoutAsterisks
                .replace(WHITESPACE, "");
 
            if (commentWordCharsOnly.length === 0) {
                return true;
            }
 
            const firstWordChar = commentWordCharsOnly[0];
 
            if (!LETTER_PATTERN.test(firstWordChar)) {
                return true;
            }
 
            // 7. Check the case of the initial word character.
            const isUppercase = firstWordChar !== firstWordChar.toLocaleLowerCase(),
                isLowercase = firstWordChar !== firstWordChar.toLocaleUpperCase();
 
            if (capitalize === "always" && isLowercase) {
                return false;
            } else if (capitalize === "never" && isUppercase) {
                return false;
            }
 
            return true;
        }
 
        /**
         * Process a comment to determine if it needs to be reported.
         *
         * @param {ASTNode} comment The comment node to process.
         * @returns {void}
         */
        function processComment(comment) {
            const options = normalizedOptions[comment.type],
                commentValid = isCommentValid(comment, options);
 
            if (!commentValid) {
                const message = capitalize === "always"
                    ? ALWAYS_MESSAGE
                    : NEVER_MESSAGE;
 
                context.report({
                    node: null,         // Intentionally using loc instead
                    loc: comment.loc,
                    message,
                    fix(fixer) {
                        const match = comment.value.match(LETTER_PATTERN);
 
                        return fixer.replaceTextRange(
 
                            // Offset match.index by 2 to account for the first 2 characters that start the comment (// or /*)
                            [comment.range[0] + match.index + 2, comment.range[0] + match.index + 3],
                            capitalize === "always" ? match[0].toLocaleUpperCase() : match[0].toLocaleLowerCase()
                        );
                    }
                });
            }
        }
 
        //----------------------------------------------------------------------
        // Public
        //----------------------------------------------------------------------
 
        return {
            Program() {
                const comments = sourceCode.getAllComments();
 
                comments.forEach(processComment);
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/class-methods-use-this.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/class-methods-use-this.js

Statements: 33.33% (6 / 18)      Branches: 0% (0 / 15)      Functions: 0% (0 / 6)      Lines: 33.33% (6 / 18)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112                      1                                                               1                   1                   1                       1                                     1                                  
/**
 * @fileoverview Rule to enforce that all class methods use 'this'.
 * @author Patrick Williams
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce that class methods utilize `this`",
            category: "Best Practices",
            recommended: false
        },
        schema: [{
            type: "object",
            properties: {
                exceptMethods: {
                    type: "array",
                    items: {
                        type: "string"
                    }
                }
            },
            additionalProperties: false
        }]
    },
    create(context) {
        const config = context.options[0] ? Object.assign({}, context.options[0]) : {};
        const exceptMethods = new Set(config.exceptMethods || []);
 
        const stack = [];
 
        /**
         * Initializes the current context to false and pushes it onto the stack.
         * These booleans represent whether 'this' has been used in the context.
         * @returns {void}
         * @private
         */
        function enterFunction() {
            stack.push(false);
        }
 
        /**
         * Check if the node is an instance method
         * @param {ASTNode} node - node to check
         * @returns {boolean} True if its an instance method
         * @private
         */
        function isInstanceMethod(node) {
            return !node.static && node.kind !== "constructor" && node.type === "MethodDefinition";
        }
 
        /**
         * Check if the node is an instance method not excluded by config
         * @param {ASTNode} node - node to check
         * @returns {boolean} True if it is an instance method, and not excluded by config
         * @private
         */
        function isIncludedInstanceMethod(node) {
            return isInstanceMethod(node) && !exceptMethods.has(node.key.name);
        }
 
        /**
         * Checks if we are leaving a function that is a method, and reports if 'this' has not been used.
         * Static methods and the constructor are exempt.
         * Then pops the context off the stack.
         * @param {ASTNode} node - A function node that was entered.
         * @returns {void}
         * @private
         */
        function exitFunction(node) {
            const methodUsesThis = stack.pop();
 
            if (isIncludedInstanceMethod(node.parent) && !methodUsesThis) {
                context.report({
                    node,
                    message: "Expected 'this' to be used by class method '{{classMethod}}'.",
                    data: {
                        classMethod: node.parent.key.name
                    }
                });
            }
        }
 
        /**
         * Mark the current context as having used 'this'.
         * @returns {void}
         * @private
         */
        function markThisUsed() {
            if (stack.length) {
                stack[stack.length - 1] = true;
            }
        }
 
        return {
            FunctionDeclaration: enterFunction,
            "FunctionDeclaration:exit": exitFunction,
            FunctionExpression: enterFunction,
            "FunctionExpression:exit": exitFunction,
            ThisExpression: markThisUsed,
            Super: markThisUsed
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/comma-dangle.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/comma-dangle.js

Statements: 19.7% (13 / 66)      Branches: 0% (0 / 60)      Functions: 0% (0 / 12)      Lines: 19.7% (13 / 66)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339                      1 1           1                             1                           1                                                         1                                                                                                                             1                                                               1                                                   1                                         1                                                                 1                                                                     1                                   1                                                                    
/**
 * @fileoverview Rule to forbid or enforce dangling commas.
 * @author Ian Christian Myers
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const lodash = require("lodash");
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const DEFAULT_OPTIONS = Object.freeze({
    arrays: "never",
    objects: "never",
    imports: "never",
    exports: "never",
    functions: "ignore"
});
 
/**
 * Checks whether or not a trailing comma is allowed in a given node.
 * If the `lastItem` is `RestElement` or `RestProperty`, it disallows trailing commas.
 *
 * @param {ASTNode} lastItem - The node of the last element in the given node.
 * @returns {boolean} `true` if a trailing comma is allowed.
 */
function isTrailingCommaAllowed(lastItem) {
    return !(
        lastItem.type === "RestElement" ||
        lastItem.type === "RestProperty" ||
        lastItem.type === "ExperimentalRestProperty"
    );
}
 
/**
 * Normalize option value.
 *
 * @param {string|Object|undefined} optionValue - The 1st option value to normalize.
 * @returns {Object} The normalized option value.
 */
function normalizeOptions(optionValue) {
    if (typeof optionValue === "string") {
        return {
            arrays: optionValue,
            objects: optionValue,
            imports: optionValue,
            exports: optionValue,
 
            // For backward compatibility, always ignore functions.
            functions: "ignore"
        };
    }
    if (typeof optionValue === "object" && optionValue !== null) {
        return {
            arrays: optionValue.arrays || DEFAULT_OPTIONS.arrays,
            objects: optionValue.objects || DEFAULT_OPTIONS.objects,
            imports: optionValue.imports || DEFAULT_OPTIONS.imports,
            exports: optionValue.exports || DEFAULT_OPTIONS.exports,
            functions: optionValue.functions || DEFAULT_OPTIONS.functions
        };
    }
 
    return DEFAULT_OPTIONS;
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require or disallow trailing commas",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "code",
 
        schema: [
            {
                defs: {
                    value: {
                        enum: [
                            "always",
                            "always-multiline",
                            "only-multiline",
                            "never"
                        ]
                    },
                    valueWithIgnore: {
                        anyOf: [
                            {
                                $ref: "#/defs/value"
                            },
                            {
                                enum: ["ignore"]
                            }
                        ]
                    }
                },
                anyOf: [
                    {
                        $ref: "#/defs/value"
                    },
                    {
                        type: "object",
                        properties: {
                            arrays: { $refs: "#/defs/valueWithIgnore" },
                            objects: { $refs: "#/defs/valueWithIgnore" },
                            imports: { $refs: "#/defs/valueWithIgnore" },
                            exports: { $refs: "#/defs/valueWithIgnore" },
                            functions: { $refs: "#/defs/valueWithIgnore" }
                        },
                        additionalProperties: false
                    }
                ]
            }
        ]
    },
 
    create(context) {
        const options = normalizeOptions(context.options[0]);
        const sourceCode = context.getSourceCode();
        const UNEXPECTED_MESSAGE = "Unexpected trailing comma.";
        const MISSING_MESSAGE = "Missing trailing comma.";
 
        /**
         * Gets the last item of the given node.
         * @param {ASTNode} node - The node to get.
         * @returns {ASTNode|null} The last node or null.
         */
        function getLastItem(node) {
            switch (node.type) {
                case "ObjectExpression":
                case "ObjectPattern":
                    return lodash.last(node.properties);
                case "ArrayExpression":
                case "ArrayPattern":
                    return lodash.last(node.elements);
                case "ImportDeclaration":
                case "ExportNamedDeclaration":
                    return lodash.last(node.specifiers);
                case "FunctionDeclaration":
                case "FunctionExpression":
                case "ArrowFunctionExpression":
                    return lodash.last(node.params);
                case "CallExpression":
                case "NewExpression":
                    return lodash.last(node.arguments);
                default:
                    return null;
            }
        }
 
        /**
         * Gets the trailing comma token of the given node.
         * If the trailing comma does not exist, this returns the token which is
         * the insertion point of the trailing comma token.
         *
         * @param {ASTNode} node - The node to get.
         * @param {ASTNode} lastItem - The last item of the node.
         * @returns {Token} The trailing comma token or the insertion point.
         */
        function getTrailingToken(node, lastItem) {
            switch (node.type) {
                case "ObjectExpression":
                case "ArrayExpression":
                case "CallExpression":
                case "NewExpression":
                    return sourceCode.getLastToken(node, 1);
                default: {
                    const nextToken = sourceCode.getTokenAfter(lastItem);
 
                    if (astUtils.isCommaToken(nextToken)) {
                        return nextToken;
                    }
                    return sourceCode.getLastToken(lastItem);
                }
            }
        }
 
        /**
         * Checks whether or not a given node is multiline.
         * This rule handles a given node as multiline when the closing parenthesis
         * and the last element are not on the same line.
         *
         * @param {ASTNode} node - A node to check.
         * @returns {boolean} `true` if the node is multiline.
         */
        function isMultiline(node) {
            const lastItem = getLastItem(node);
 
            if (!lastItem) {
                return false;
            }
 
            const penultimateToken = getTrailingToken(node, lastItem);
            const lastToken = sourceCode.getTokenAfter(penultimateToken);
 
            return lastToken.loc.end.line !== penultimateToken.loc.end.line;
        }
 
        /**
         * Reports a trailing comma if it exists.
         *
         * @param {ASTNode} node - A node to check. Its type is one of
         *   ObjectExpression, ObjectPattern, ArrayExpression, ArrayPattern,
         *   ImportDeclaration, and ExportNamedDeclaration.
         * @returns {void}
         */
        function forbidTrailingComma(node) {
            const lastItem = getLastItem(node);
 
            if (!lastItem || (node.type === "ImportDeclaration" && lastItem.type !== "ImportSpecifier")) {
                return;
            }
 
            const trailingToken = getTrailingToken(node, lastItem);
 
            if (astUtils.isCommaToken(trailingToken)) {
                context.report({
                    node: lastItem,
                    loc: trailingToken.loc.start,
                    message: UNEXPECTED_MESSAGE,
                    fix(fixer) {
                        return fixer.remove(trailingToken);
                    }
                });
            }
        }
 
        /**
         * Reports the last element of a given node if it does not have a trailing
         * comma.
         *
         * If a given node is `ArrayPattern` which has `RestElement`, the trailing
         * comma is disallowed, so report if it exists.
         *
         * @param {ASTNode} node - A node to check. Its type is one of
         *   ObjectExpression, ObjectPattern, ArrayExpression, ArrayPattern,
         *   ImportDeclaration, and ExportNamedDeclaration.
         * @returns {void}
         */
        function forceTrailingComma(node) {
            const lastItem = getLastItem(node);
 
            if (!lastItem || (node.type === "ImportDeclaration" && lastItem.type !== "ImportSpecifier")) {
                return;
            }
            if (!isTrailingCommaAllowed(lastItem)) {
                forbidTrailingComma(node);
                return;
            }
 
            const trailingToken = getTrailingToken(node, lastItem);
 
            if (trailingToken.value !== ",") {
                context.report({
                    node: lastItem,
                    loc: trailingToken.loc.end,
                    message: MISSING_MESSAGE,
                    fix(fixer) {
                        return fixer.insertTextAfter(trailingToken, ",");
                    }
                });
            }
        }
 
        /**
         * If a given node is multiline, reports the last element of a given node
         * when it does not have a trailing comma.
         * Otherwise, reports a trailing comma if it exists.
         *
         * @param {ASTNode} node - A node to check. Its type is one of
         *   ObjectExpression, ObjectPattern, ArrayExpression, ArrayPattern,
         *   ImportDeclaration, and ExportNamedDeclaration.
         * @returns {void}
         */
        function forceTrailingCommaIfMultiline(node) {
            if (isMultiline(node)) {
                forceTrailingComma(node);
            } else {
                forbidTrailingComma(node);
            }
        }
 
        /**
         * Only if a given node is not multiline, reports the last element of a given node
         * when it does not have a trailing comma.
         * Otherwise, reports a trailing comma if it exists.
         *
         * @param {ASTNode} node - A node to check. Its type is one of
         *   ObjectExpression, ObjectPattern, ArrayExpression, ArrayPattern,
         *   ImportDeclaration, and ExportNamedDeclaration.
         * @returns {void}
         */
        function allowTrailingCommaIfMultiline(node) {
            if (!isMultiline(node)) {
                forbidTrailingComma(node);
            }
        }
 
        const predicate = {
            always: forceTrailingComma,
            "always-multiline": forceTrailingCommaIfMultiline,
            "only-multiline": allowTrailingCommaIfMultiline,
            never: forbidTrailingComma,
            ignore: lodash.noop
        };
 
        return {
            ObjectExpression: predicate[options.objects],
            ObjectPattern: predicate[options.objects],
 
            ArrayExpression: predicate[options.arrays],
            ArrayPattern: predicate[options.arrays],
 
            ImportDeclaration: predicate[options.imports],
 
            ExportNamedDeclaration: predicate[options.exports],
 
            FunctionDeclaration: predicate[options.functions],
            FunctionExpression: predicate[options.functions],
            ArrowFunctionExpression: predicate[options.functions],
            CallExpression: predicate[options.functions],
            NewExpression: predicate[options.functions]
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/comma-spacing.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/comma-spacing.js

Statements: 10.87% (5 / 46)      Branches: 0% (0 / 43)      Functions: 0% (0 / 6)      Lines: 10.87% (5 / 46)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185            1           1                                                                                                     1                                                                                       1                                             1                                                                                                            
/**
 * @fileoverview Comma spacing - validates spacing before and after comma
 * @author Vignesh Anand aka vegetableman.
 */
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent spacing before and after commas",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                type: "object",
                properties: {
                    before: {
                        type: "boolean"
                    },
                    after: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        const sourceCode = context.getSourceCode();
        const tokensAndComments = sourceCode.tokensAndComments;
 
        const options = {
            before: context.options[0] ? !!context.options[0].before : false,
            after: context.options[0] ? !!context.options[0].after : true
        };
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        // list of comma tokens to ignore for the check of leading whitespace
        const commaTokensToIgnore = [];
 
        /**
         * Reports a spacing error with an appropriate message.
         * @param {ASTNode} node The binary expression node to report.
         * @param {string} dir Is the error "before" or "after" the comma?
         * @param {ASTNode} otherNode The node at the left or right of `node`
         * @returns {void}
         * @private
         */
        function report(node, dir, otherNode) {
            context.report({
                node,
                fix(fixer) {
                    if (options[dir]) {
                        if (dir === "before") {
                            return fixer.insertTextBefore(node, " ");
                        }
                        return fixer.insertTextAfter(node, " ");
 
                    }
                    let start, end;
                    const newText = "";
 
                    if (dir === "before") {
                        start = otherNode.range[1];
                        end = node.range[0];
                    } else {
                        start = node.range[1];
                        end = otherNode.range[0];
                    }
 
                    return fixer.replaceTextRange([start, end], newText);
 
                },
                message: options[dir]
                  ? "A space is required {{dir}} ','."
                  : "There should be no space {{dir}} ','.",
                data: {
                    dir
                }
            });
        }
 
        /**
         * Validates the spacing around a comma token.
         * @param {Object} tokens - The tokens to be validated.
         * @param {Token} tokens.comma The token representing the comma.
         * @param {Token} [tokens.left] The last token before the comma.
         * @param {Token} [tokens.right] The first token after the comma.
         * @param {Token|ASTNode} reportItem The item to use when reporting an error.
         * @returns {void}
         * @private
         */
        function validateCommaItemSpacing(tokens, reportItem) {
            if (tokens.left && astUtils.isTokenOnSameLine(tokens.left, tokens.comma) &&
                    (options.before !== sourceCode.isSpaceBetweenTokens(tokens.left, tokens.comma))
            ) {
                report(reportItem, "before", tokens.left);
            }
 
            if (tokens.right && !options.after && tokens.right.type === "Line") {
                return;
            }
 
            if (tokens.right && astUtils.isTokenOnSameLine(tokens.comma, tokens.right) &&
                    (options.after !== sourceCode.isSpaceBetweenTokens(tokens.comma, tokens.right))
            ) {
                report(reportItem, "after", tokens.right);
            }
        }
 
        /**
         * Adds null elements of the given ArrayExpression or ArrayPattern node to the ignore list.
         * @param {ASTNode} node An ArrayExpression or ArrayPattern node.
         * @returns {void}
         */
        function addNullElementsToIgnoreList(node) {
            let previousToken = sourceCode.getFirstToken(node);
 
            node.elements.forEach(element => {
                let token;
 
                if (element === null) {
                    token = sourceCode.getTokenAfter(previousToken);
 
                    if (astUtils.isCommaToken(token)) {
                        commaTokensToIgnore.push(token);
                    }
                } else {
                    token = sourceCode.getTokenAfter(element);
                }
 
                previousToken = token;
            });
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            "Program:exit"() {
                tokensAndComments.forEach((token, i) => {
 
                    if (!astUtils.isCommaToken(token)) {
                        return;
                    }
 
                    if (token && token.type === "JSXText") {
                        return;
                    }
 
                    const previousToken = tokensAndComments[i - 1];
                    const nextToken = tokensAndComments[i + 1];
 
                    validateCommaItemSpacing({
                        comma: token,
                        left: astUtils.isCommaToken(previousToken) || commaTokensToIgnore.indexOf(token) > -1 ? null : previousToken,
                        right: astUtils.isCommaToken(nextToken) ? null : nextToken
                    }, token);
                });
            },
            ArrayExpression: addNullElementsToIgnoreList,
            ArrayPattern: addNullElementsToIgnoreList
 
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/comma-style.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/comma-style.js

Statements: 7.89% (6 / 76)      Branches: 0% (0 / 72)      Functions: 0% (0 / 16)      Lines: 7.89% (6 / 76)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299              1           1                                                                                                                     1                                                 1                                       1                                                                                                     1                                                                                                                                                                                                                                                                    
/**
 * @fileoverview Comma style - enforces comma styles of two types: last and first
 * @author Vignesh Anand aka vegetableman
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent comma style",
            category: "Stylistic Issues",
            recommended: false
        },
        fixable: "code",
        schema: [
            {
                enum: ["first", "last"]
            },
            {
                type: "object",
                properties: {
                    exceptions: {
                        type: "object",
                        additionalProperties: {
                            type: "boolean"
                        }
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const style = context.options[0] || "last",
            sourceCode = context.getSourceCode();
        const exceptions = {
            ArrayPattern: true,
            ArrowFunctionExpression: true,
            CallExpression: true,
            FunctionDeclaration: true,
            FunctionExpression: true,
            ImportDeclaration: true,
            ObjectPattern: true
        };
 
        if (context.options.length === 2 && context.options[1].hasOwnProperty("exceptions")) {
            const keys = Object.keys(context.options[1].exceptions);
 
            for (let i = 0; i < keys.length; i++) {
                exceptions[keys[i]] = context.options[1].exceptions[keys[i]];
            }
        }
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Modified text based on the style
         * @param {string} styleType Style type
         * @param {string} text Source code text
         * @returns {string} modified text
         * @private
         */
        function getReplacedText(styleType, text) {
            switch (styleType) {
                case "between":
                    return `,${text.replace("\n", "")}`;
 
                case "first":
                    return `${text},`;
 
                case "last":
                    return `,${text}`;
 
                default:
                    return "";
            }
        }
 
        /**
         * Determines the fixer function for a given style.
         * @param {string} styleType comma style
         * @param {ASTNode} previousItemToken The token to check.
         * @param {ASTNode} commaToken The token to check.
         * @param {ASTNode} currentItemToken The token to check.
         * @returns {Function} Fixer function
         * @private
         */
        function getFixerFunction(styleType, previousItemToken, commaToken, currentItemToken) {
            const text =
                sourceCode.text.slice(previousItemToken.range[1], commaToken.range[0]) +
                sourceCode.text.slice(commaToken.range[1], currentItemToken.range[0]);
            const range = [previousItemToken.range[1], currentItemToken.range[0]];
 
            return function(fixer) {
                return fixer.replaceTextRange(range, getReplacedText(styleType, text));
            };
        }
 
        /**
         * Validates the spacing around single items in lists.
         * @param {Token} previousItemToken The last token from the previous item.
         * @param {Token} commaToken The token representing the comma.
         * @param {Token} currentItemToken The first token of the current item.
         * @param {Token} reportItem The item to use when reporting an error.
         * @returns {void}
         * @private
         */
        function validateCommaItemSpacing(previousItemToken, commaToken, currentItemToken, reportItem) {
 
            // if single line
            if (astUtils.isTokenOnSameLine(commaToken, currentItemToken) &&
                    astUtils.isTokenOnSameLine(previousItemToken, commaToken)) {
 
                // do nothing.
 
            } else if (!astUtils.isTokenOnSameLine(commaToken, currentItemToken) &&
                    !astUtils.isTokenOnSameLine(previousItemToken, commaToken)) {
 
                // lone comma
                context.report({
                    node: reportItem,
                    loc: {
                        line: commaToken.loc.end.line,
                        column: commaToken.loc.start.column
                    },
                    message: "Bad line breaking before and after ','.",
                    fix: getFixerFunction("between", previousItemToken, commaToken, currentItemToken)
                });
 
            } else if (style === "first" && !astUtils.isTokenOnSameLine(commaToken, currentItemToken)) {
 
                context.report({
                    node: reportItem,
                    message: "',' should be placed first.",
                    fix: getFixerFunction(style, previousItemToken, commaToken, currentItemToken)
                });
 
            } else if (style === "last" && astUtils.isTokenOnSameLine(commaToken, currentItemToken)) {
 
                context.report({
                    node: reportItem,
                    loc: {
                        line: commaToken.loc.end.line,
                        column: commaToken.loc.end.column
                    },
                    message: "',' should be placed last.",
                    fix: getFixerFunction(style, previousItemToken, commaToken, currentItemToken)
                });
            }
        }
 
        /**
         * Checks the comma placement with regards to a declaration/property/element
         * @param {ASTNode} node The binary expression node to check
         * @param {string} property The property of the node containing child nodes.
         * @private
         * @returns {void}
         */
        function validateComma(node, property) {
            const items = node[property],
                arrayLiteral = (node.type === "ArrayExpression" || node.type === "ArrayPattern");
 
            if (items.length > 1 || arrayLiteral) {
 
                // seed as opening [
                let previousItemToken = sourceCode.getFirstToken(node);
 
                items.forEach(item => {
                    const commaToken = item ? sourceCode.getTokenBefore(item) : previousItemToken,
                        currentItemToken = item ? sourceCode.getFirstToken(item) : sourceCode.getTokenAfter(commaToken),
                        reportItem = item || currentItemToken,
                        tokenBeforeComma = sourceCode.getTokenBefore(commaToken);
 
                    // Check if previous token is wrapped in parentheses
                    if (tokenBeforeComma && astUtils.isClosingParenToken(tokenBeforeComma)) {
                        previousItemToken = tokenBeforeComma;
                    }
 
                    /*
                     * This works by comparing three token locations:
                     * - previousItemToken is the last token of the previous item
                     * - commaToken is the location of the comma before the current item
                     * - currentItemToken is the first token of the current item
                     *
                     * These values get switched around if item is undefined.
                     * previousItemToken will refer to the last token not belonging
                     * to the current item, which could be a comma or an opening
                     * square bracket. currentItemToken could be a comma.
                     *
                     * All comparisons are done based on these tokens directly, so
                     * they are always valid regardless of an undefined item.
                     */
                    if (astUtils.isCommaToken(commaToken)) {
                        validateCommaItemSpacing(previousItemToken, commaToken,
                                currentItemToken, reportItem);
                    }
 
                    if (item) {
                        const tokenAfterItem = sourceCode.getTokenAfter(item, astUtils.isNotClosingParenToken);
 
                        previousItemToken = tokenAfterItem ? sourceCode.getTokenBefore(tokenAfterItem) : sourceCode.ast.tokens[sourceCode.ast.tokens.length - 1];
                    }
                });
 
                /*
                 * Special case for array literals that have empty last items, such
                 * as [ 1, 2, ]. These arrays only have two items show up in the
                 * AST, so we need to look at the token to verify that there's no
                 * dangling comma.
                 */
                if (arrayLiteral) {
 
                    const lastToken = sourceCode.getLastToken(node),
                        nextToLastToken = sourceCode.getTokenBefore(lastToken);
 
                    if (astUtils.isCommaToken(nextToLastToken)) {
                        validateCommaItemSpacing(
                            sourceCode.getTokenBefore(nextToLastToken),
                            nextToLastToken,
                            lastToken,
                            lastToken
                        );
                    }
                }
            }
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        const nodes = {};
 
        if (!exceptions.VariableDeclaration) {
            nodes.VariableDeclaration = function(node) {
                validateComma(node, "declarations");
            };
        }
        if (!exceptions.ObjectExpression) {
            nodes.ObjectExpression = function(node) {
                validateComma(node, "properties");
            };
        }
        if (!exceptions.ObjectPattern) {
            nodes.ObjectPattern = function(node) {
                validateComma(node, "properties");
            };
        }
        if (!exceptions.ArrayExpression) {
            nodes.ArrayExpression = function(node) {
                validateComma(node, "elements");
            };
        }
        if (!exceptions.ArrayPattern) {
            nodes.ArrayPattern = function(node) {
                validateComma(node, "elements");
            };
        }
        if (!exceptions.FunctionDeclaration) {
            nodes.FunctionDeclaration = function(node) {
                validateComma(node, "params");
            };
        }
        if (!exceptions.FunctionExpression) {
            nodes.FunctionExpression = function(node) {
                validateComma(node, "params");
            };
        }
        if (!exceptions.ArrowFunctionExpression) {
            nodes.ArrowFunctionExpression = function(node) {
                validateComma(node, "params");
            };
        }
        if (!exceptions.CallExpression) {
            nodes.CallExpression = function(node) {
                validateComma(node, "arguments");
            };
        }
        if (!exceptions.ImportDeclaration) {
            nodes.ImportDeclaration = function(node) {
                validateComma(node, "specifiers");
            };
        }
 
        return nodes;
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/complexity.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/complexity.js

Statements: 27.59% (8 / 29)      Branches: 0% (0 / 20)      Functions: 0% (0 / 6)      Lines: 27.59% (8 / 29)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170                        1   1           1                                                                                                                       1                   1                                   1                       1                           1                                                                      
/**
 * @fileoverview Counts the cyclomatic complexity of each function of the script. See http://en.wikipedia.org/wiki/Cyclomatic_complexity.
 * Counts the number of if, conditional, for, whilte, try, switch/case,
 * @author Patrick Brosset
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const lodash = require("lodash");
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce a maximum cyclomatic complexity allowed in a program",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [
            {
                oneOf: [
                    {
                        type: "integer",
                        minimum: 0
                    },
                    {
                        type: "object",
                        properties: {
                            maximum: {
                                type: "integer",
                                minimum: 0
                            },
                            max: {
                                type: "integer",
                                minimum: 0
                            }
                        },
                        additionalProperties: false
                    }
                ]
            }
        ]
    },
 
    create(context) {
        const option = context.options[0];
        let THRESHOLD = 20;
 
        if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") {
            THRESHOLD = option.maximum;
        }
        if (typeof option === "object" && option.hasOwnProperty("max") && typeof option.max === "number") {
            THRESHOLD = option.max;
        }
        if (typeof option === "number") {
            THRESHOLD = option;
        }
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        // Using a stack to store complexity (handling nested functions)
        const fns = [];
 
        /**
         * When parsing a new function, store it in our function stack
         * @returns {void}
         * @private
         */
        function startFunction() {
            fns.push(1);
        }
 
        /**
         * Evaluate the node at the end of function
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function endFunction(node) {
            const name = lodash.upperFirst(astUtils.getFunctionNameWithKind(node));
            const complexity = fns.pop();
 
            if (complexity > THRESHOLD) {
                context.report({
                    node,
                    message: "{{name}} has a complexity of {{complexity}}.",
                    data: { name, complexity }
                });
            }
        }
 
        /**
         * Increase the complexity of the function in context
         * @returns {void}
         * @private
         */
        function increaseComplexity() {
            if (fns.length) {
                fns[fns.length - 1]++;
            }
        }
 
        /**
         * Increase the switch complexity in context
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function increaseSwitchComplexity(node) {
 
            // Avoiding `default`
            if (node.test) {
                increaseComplexity(node);
            }
        }
 
        /**
         * Increase the logical path complexity in context
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function increaseLogicalComplexity(node) {
 
            // Avoiding &&
            if (node.operator === "||") {
                increaseComplexity(node);
            }
        }
 
        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------
 
        return {
            FunctionDeclaration: startFunction,
            FunctionExpression: startFunction,
            ArrowFunctionExpression: startFunction,
            "FunctionDeclaration:exit": endFunction,
            "FunctionExpression:exit": endFunction,
            "ArrowFunctionExpression:exit": endFunction,
 
            CatchClause: increaseComplexity,
            ConditionalExpression: increaseComplexity,
            LogicalExpression: increaseLogicalComplexity,
            ForStatement: increaseComplexity,
            ForInStatement: increaseComplexity,
            ForOfStatement: increaseComplexity,
            IfStatement: increaseComplexity,
            SwitchCase: increaseSwitchComplexity,
            WhileStatement: increaseComplexity,
            DoWhileStatement: increaseComplexity
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/computed-property-spacing.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/computed-property-spacing.js

Statements: 20% (7 / 35)      Branches: 0% (0 / 22)      Functions: 0% (0 / 11)      Lines: 20% (7 / 35)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178            1           1                                                               1                                         1                                       1                                       1                                       1                                                                                                        
/**
 * @fileoverview Disallows or enforces spaces inside computed properties.
 * @author Jamund Ferguson
 */
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent spacing inside computed property brackets",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                enum: ["always", "never"]
            }
        ]
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
        const propertyNameMustBeSpaced = context.options[0] === "always"; // default is "never"
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
        * Reports that there shouldn't be a space after the first token
        * @param {ASTNode} node - The node to report in the event of an error.
        * @param {Token} token - The token to use for the report.
        * @param {Token} tokenAfter - The token after `token`.
        * @returns {void}
        */
        function reportNoBeginningSpace(node, token, tokenAfter) {
            context.report({
                node,
                loc: token.loc.start,
                message: "There should be no space after '{{tokenValue}}'.",
                data: {
                    tokenValue: token.value
                },
                fix(fixer) {
                    return fixer.removeRange([token.range[1], tokenAfter.range[0]]);
                }
            });
        }
 
        /**
        * Reports that there shouldn't be a space before the last token
        * @param {ASTNode} node - The node to report in the event of an error.
        * @param {Token} token - The token to use for the report.
        * @param {Token} tokenBefore - The token before `token`.
        * @returns {void}
        */
        function reportNoEndingSpace(node, token, tokenBefore) {
            context.report({
                node,
                loc: token.loc.start,
                message: "There should be no space before '{{tokenValue}}'.",
                data: {
                    tokenValue: token.value
                },
                fix(fixer) {
                    return fixer.removeRange([tokenBefore.range[1], token.range[0]]);
                }
            });
        }
 
        /**
        * Reports that there should be a space after the first token
        * @param {ASTNode} node - The node to report in the event of an error.
        * @param {Token} token - The token to use for the report.
        * @returns {void}
        */
        function reportRequiredBeginningSpace(node, token) {
            context.report({
                node,
                loc: token.loc.start,
                message: "A space is required after '{{tokenValue}}'.",
                data: {
                    tokenValue: token.value
                },
                fix(fixer) {
                    return fixer.insertTextAfter(token, " ");
                }
            });
        }
 
        /**
        * Reports that there should be a space before the last token
        * @param {ASTNode} node - The node to report in the event of an error.
        * @param {Token} token - The token to use for the report.
        * @returns {void}
        */
        function reportRequiredEndingSpace(node, token) {
            context.report({
                node,
                loc: token.loc.start,
                message: "A space is required before '{{tokenValue}}'.",
                data: {
                    tokenValue: token.value
                },
                fix(fixer) {
                    return fixer.insertTextBefore(token, " ");
                }
            });
        }
 
        /**
         * Returns a function that checks the spacing of a node on the property name
         * that was passed in.
         * @param {string} propertyName The property on the node to check for spacing
         * @returns {Function} A function that will check spacing on a node
         */
        function checkSpacing(propertyName) {
            return function(node) {
                if (!node.computed) {
                    return;
                }
 
                const property = node[propertyName];
 
                const before = sourceCode.getTokenBefore(property),
                    first = sourceCode.getFirstToken(property),
                    last = sourceCode.getLastToken(property),
                    after = sourceCode.getTokenAfter(property);
 
                if (astUtils.isTokenOnSameLine(before, first)) {
                    if (propertyNameMustBeSpaced) {
                        if (!sourceCode.isSpaceBetweenTokens(before, first) && astUtils.isTokenOnSameLine(before, first)) {
                            reportRequiredBeginningSpace(node, before);
                        }
                    } else {
                        if (sourceCode.isSpaceBetweenTokens(before, first)) {
                            reportNoBeginningSpace(node, before, first);
                        }
                    }
                }
 
                if (astUtils.isTokenOnSameLine(last, after)) {
                    if (propertyNameMustBeSpaced) {
                        if (!sourceCode.isSpaceBetweenTokens(last, after) && astUtils.isTokenOnSameLine(last, after)) {
                            reportRequiredEndingSpace(node, after);
                        }
                    } else {
                        if (sourceCode.isSpaceBetweenTokens(last, after)) {
                            reportNoEndingSpace(node, after, last);
                        }
                    }
                }
            };
        }
 
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            Property: checkSpacing("key"),
            MemberExpression: checkSpacing("property")
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/consistent-return.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/consistent-return.js

Statements: 17.07% (7 / 41)      Branches: 0% (0 / 41)      Functions: 0% (0 / 8)      Lines: 17.07% (7 / 41)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190                    1   1                       1                 1                 1                     1                                                             1                                                                                                                                                                                                                  
/**
 * @fileoverview Rule to flag consistent return values
 * @author Nicholas C. Zakas
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const lodash = require("lodash");
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks whether or not a given node is an `Identifier` node which was named a given name.
 * @param {ASTNode} node - A node to check.
 * @param {string} name - An expected name of the node.
 * @returns {boolean} `true` if the node is an `Identifier` node which was named as expected.
 */
function isIdentifier(node, name) {
    return node.type === "Identifier" && node.name === name;
}
 
/**
 * Checks whether or not a given code path segment is unreachable.
 * @param {CodePathSegment} segment - A CodePathSegment to check.
 * @returns {boolean} `true` if the segment is unreachable.
 */
function isUnreachable(segment) {
    return !segment.reachable;
}
 
/**
* Checks whether a given node is a `constructor` method in an ES6 class
* @param {ASTNode} node A node to check
* @returns {boolean} `true` if the node is a `constructor` method
*/
function isClassConstructor(node) {
    return node.type === "FunctionExpression" &&
        node.parent &&
        node.parent.type === "MethodDefinition" &&
        node.parent.kind === "constructor";
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require `return` statements to either always or never specify values",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [{
            type: "object",
            properties: {
                treatUndefinedAsUnspecified: {
                    type: "boolean"
                }
            },
            additionalProperties: false
        }]
    },
 
    create(context) {
        const options = context.options[0] || {};
        const treatUndefinedAsUnspecified = options.treatUndefinedAsUnspecified === true;
        let funcInfo = null;
 
        /**
         * Checks whether of not the implicit returning is consistent if the last
         * code path segment is reachable.
         *
         * @param {ASTNode} node - A program/function node to check.
         * @returns {void}
         */
        function checkLastSegment(node) {
            let loc, name;
 
            /*
             * Skip if it expected no return value or unreachable.
             * When unreachable, all paths are returned or thrown.
             */
            if (!funcInfo.hasReturnValue ||
                funcInfo.codePath.currentSegments.every(isUnreachable) ||
                astUtils.isES5Constructor(node) ||
                isClassConstructor(node)
            ) {
                return;
            }
 
            // Adjust a location and a message.
            if (node.type === "Program") {
 
                // The head of program.
                loc = { line: 1, column: 0 };
                name = "program";
            } else if (node.type === "ArrowFunctionExpression") {
 
                // `=>` token
                loc = context.getSourceCode().getTokenBefore(node.body, astUtils.isArrowToken).loc.start;
            } else if (
                node.parent.type === "MethodDefinition" ||
                (node.parent.type === "Property" && node.parent.method)
            ) {
 
                // Method name.
                loc = node.parent.key.loc.start;
            } else {
 
                // Function name or `function` keyword.
                loc = (node.id || node).loc.start;
            }
 
            if (!name) {
                name = astUtils.getFunctionNameWithKind(node);
            }
 
            // Reports.
            context.report({
                node,
                loc,
                message: "Expected to return a value at the end of {{name}}.",
                data: { name }
            });
        }
 
        return {
 
            // Initializes/Disposes state of each code path.
            onCodePathStart(codePath, node) {
                funcInfo = {
                    upper: funcInfo,
                    codePath,
                    hasReturn: false,
                    hasReturnValue: false,
                    message: "",
                    node
                };
            },
            onCodePathEnd() {
                funcInfo = funcInfo.upper;
            },
 
            // Reports a given return statement if it's inconsistent.
            ReturnStatement(node) {
                const argument = node.argument;
                let hasReturnValue = Boolean(argument);
 
                if (treatUndefinedAsUnspecified && hasReturnValue) {
                    hasReturnValue = !isIdentifier(argument, "undefined") && argument.operator !== "void";
                }
 
                if (!funcInfo.hasReturn) {
                    funcInfo.hasReturn = true;
                    funcInfo.hasReturnValue = hasReturnValue;
                    funcInfo.message = "{{name}} expected {{which}} return value.";
                    funcInfo.data = {
                        name: funcInfo.node.type === "Program"
                            ? "Program"
                            : lodash.upperFirst(astUtils.getFunctionNameWithKind(funcInfo.node)),
                        which: hasReturnValue ? "a" : "no"
                    };
                } else if (funcInfo.hasReturnValue !== hasReturnValue) {
                    context.report({
                        node,
                        message: funcInfo.message,
                        data: funcInfo.data
                    });
                }
            },
 
            // Reports a given program/function if the implicit returning is not consistent.
            "Program:exit": checkLastSegment,
            "FunctionDeclaration:exit": checkLastSegment,
            "FunctionExpression:exit": checkLastSegment,
            "ArrowFunctionExpression:exit": checkLastSegment
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/consistent-this.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/consistent-this.js

Statements: 13.16% (5 / 38)      Branches: 0% (0 / 31)      Functions: 0% (0 / 7)      Lines: 13.89% (5 / 36)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143                    1                                                                   1                       1                                       1                                                                 1                                                                  
/**
 * @fileoverview Rule to enforce consistent naming of "this" context variables
 * @author Raphael Pigulla
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent naming when capturing the current execution context",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: {
            type: "array",
            items: {
                type: "string",
                minLength: 1
            },
            uniqueItems: true
        }
    },
 
    create(context) {
        let aliases = [];
 
        if (context.options.length === 0) {
            aliases.push("that");
        } else {
            aliases = context.options;
        }
 
        /**
         * Reports that a variable declarator or assignment expression is assigning
         * a non-'this' value to the specified alias.
         * @param {ASTNode} node - The assigning node.
         * @param {string} alias - the name of the alias that was incorrectly used.
         * @returns {void}
         */
        function reportBadAssignment(node, alias) {
            context.report({ node, message: "Designated alias '{{alias}}' is not assigned to 'this'.", data: { alias } });
        }
 
        /**
         * Checks that an assignment to an identifier only assigns 'this' to the
         * appropriate alias, and the alias is only assigned to 'this'.
         * @param {ASTNode} node - The assigning node.
         * @param {Identifier} name - The name of the variable assigned to.
         * @param {Expression} value - The value of the assignment.
         * @returns {void}
         */
        function checkAssignment(node, name, value) {
            const isThis = value.type === "ThisExpression";
 
            if (aliases.indexOf(name) !== -1) {
                if (!isThis || node.operator && node.operator !== "=") {
                    reportBadAssignment(node, name);
                }
            } else if (isThis) {
                context.report({ node, message: "Unexpected alias '{{name}}' for 'this'.", data: { name } });
            }
        }
 
        /**
         * Ensures that a variable declaration of the alias in a program or function
         * is assigned to the correct value.
         * @param {string} alias alias the check the assignment of.
         * @param {Object} scope scope of the current code we are checking.
         * @private
         * @returns {void}
         */
        function checkWasAssigned(alias, scope) {
            const variable = scope.set.get(alias);
 
            if (!variable) {
                return;
            }
 
            if (variable.defs.some(def => def.node.type === "VariableDeclarator" &&
                def.node.init !== null)) {
                return;
            }
 
            // The alias has been declared and not assigned: check it was
            // assigned later in the same scope.
            if (!variable.references.some(reference => {
                const write = reference.writeExpr;
 
                return (
                    reference.from === scope &&
                    write && write.type === "ThisExpression" &&
                    write.parent.operator === "="
                );
            })) {
                variable.defs.map(def => def.node).forEach(node => {
                    reportBadAssignment(node, alias);
                });
            }
        }
 
        /**
         * Check each alias to ensure that is was assinged to the correct value.
         * @returns {void}
         */
        function ensureWasAssigned() {
            const scope = context.getScope();
 
            aliases.forEach(alias => {
                checkWasAssigned(alias, scope);
            });
        }
 
        return {
            "Program:exit": ensureWasAssigned,
            "FunctionExpression:exit": ensureWasAssigned,
            "FunctionDeclaration:exit": ensureWasAssigned,
 
            VariableDeclarator(node) {
                const id = node.id;
                const isDestructuring =
                    id.type === "ArrayPattern" || id.type === "ObjectPattern";
 
                if (node.init !== null && !isDestructuring) {
                    checkAssignment(node, id.name, node.init);
                }
            },
 
            AssignmentExpression(node) {
                if (node.left.type === "Identifier") {
                    checkAssignment(node, node.left.name, node.right);
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/constructor-super.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/constructor-super.js

Statements: 6.38% (6 / 94)      Branches: 0% (0 / 85)      Functions: 0% (0 / 13)      Lines: 6.38% (6 / 94)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387                                  1                     1                           1                                                                                                   1                                                                           1                 1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
/**
 * @fileoverview A rule to verify `super()` callings in constructor.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks whether a given code path segment is reachable or not.
 *
 * @param {CodePathSegment} segment - A code path segment to check.
 * @returns {boolean} `true` if the segment is reachable.
 */
function isReachable(segment) {
    return segment.reachable;
}
 
/**
 * Checks whether or not a given node is a constructor.
 * @param {ASTNode} node - A node to check. This node type is one of
 *   `Program`, `FunctionDeclaration`, `FunctionExpression`, and
 *   `ArrowFunctionExpression`.
 * @returns {boolean} `true` if the node is a constructor.
 */
function isConstructorFunction(node) {
    return (
        node.type === "FunctionExpression" &&
        node.parent.type === "MethodDefinition" &&
        node.parent.kind === "constructor"
    );
}
 
/**
 * Checks whether a given node can be a constructor or not.
 *
 * @param {ASTNode} node - A node to check.
 * @returns {boolean} `true` if the node can be a constructor.
 */
function isPossibleConstructor(node) {
    if (!node) {
        return false;
    }
 
    switch (node.type) {
        case "ClassExpression":
        case "FunctionExpression":
        case "ThisExpression":
        case "MemberExpression":
        case "CallExpression":
        case "NewExpression":
        case "YieldExpression":
        case "TaggedTemplateExpression":
        case "MetaProperty":
            return true;
 
        case "Identifier":
            return node.name !== "undefined";
 
        case "AssignmentExpression":
            return isPossibleConstructor(node.right);
 
        case "LogicalExpression":
            return (
                isPossibleConstructor(node.left) ||
                isPossibleConstructor(node.right)
            );
 
        case "ConditionalExpression":
            return (
                isPossibleConstructor(node.alternate) ||
                isPossibleConstructor(node.consequent)
            );
 
        case "SequenceExpression": {
            const lastExpression = node.expressions[node.expressions.length - 1];
 
            return isPossibleConstructor(lastExpression);
        }
 
        default:
            return false;
    }
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require `super()` calls in constructors",
            category: "ECMAScript 6",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
 
        /*
         * {{hasExtends: boolean, scope: Scope, codePath: CodePath}[]}
         * Information for each constructor.
         * - upper:      Information of the upper constructor.
         * - hasExtends: A flag which shows whether own class has a valid `extends`
         *               part.
         * - scope:      The scope of own class.
         * - codePath:   The code path object of the constructor.
         */
        let funcInfo = null;
 
        /*
         * {Map<string, {calledInSomePaths: boolean, calledInEveryPaths: boolean}>}
         * Information for each code path segment.
         * - calledInSomePaths:  A flag of be called `super()` in some code paths.
         * - calledInEveryPaths: A flag of be called `super()` in all code paths.
         * - validNodes:
         */
        let segInfoMap = Object.create(null);
 
        /**
         * Gets the flag which shows `super()` is called in some paths.
         * @param {CodePathSegment} segment - A code path segment to get.
         * @returns {boolean} The flag which shows `super()` is called in some paths
         */
        function isCalledInSomePath(segment) {
            return segment.reachable && segInfoMap[segment.id].calledInSomePaths;
        }
 
        /**
         * Gets the flag which shows `super()` is called in all paths.
         * @param {CodePathSegment} segment - A code path segment to get.
         * @returns {boolean} The flag which shows `super()` is called in all paths.
         */
        function isCalledInEveryPath(segment) {
 
            /*
             * If specific segment is the looped segment of the current segment,
             * skip the segment.
             * If not skipped, this never becomes true after a loop.
             */
            if (segment.nextSegments.length === 1 &&
                segment.nextSegments[0].isLoopedPrevSegment(segment)
            ) {
                return true;
            }
            return segment.reachable && segInfoMap[segment.id].calledInEveryPaths;
        }
 
        return {
 
            /**
             * Stacks a constructor information.
             * @param {CodePath} codePath - A code path which was started.
             * @param {ASTNode} node - The current node.
             * @returns {void}
             */
            onCodePathStart(codePath, node) {
                if (isConstructorFunction(node)) {
 
                    // Class > ClassBody > MethodDefinition > FunctionExpression
                    const classNode = node.parent.parent.parent;
                    const superClass = classNode.superClass;
 
                    funcInfo = {
                        upper: funcInfo,
                        isConstructor: true,
                        hasExtends: Boolean(superClass),
                        superIsConstructor: isPossibleConstructor(superClass),
                        codePath
                    };
                } else {
                    funcInfo = {
                        upper: funcInfo,
                        isConstructor: false,
                        hasExtends: false,
                        superIsConstructor: false,
                        codePath
                    };
                }
            },
 
            /**
             * Pops a constructor information.
             * And reports if `super()` lacked.
             * @param {CodePath} codePath - A code path which was ended.
             * @param {ASTNode} node - The current node.
             * @returns {void}
             */
            onCodePathEnd(codePath, node) {
                const hasExtends = funcInfo.hasExtends;
 
                // Pop.
                funcInfo = funcInfo.upper;
 
                if (!hasExtends) {
                    return;
                }
 
                // Reports if `super()` lacked.
                const segments = codePath.returnedSegments;
                const calledInEveryPaths = segments.every(isCalledInEveryPath);
                const calledInSomePaths = segments.some(isCalledInSomePath);
 
                if (!calledInEveryPaths) {
                    context.report({
                        message: calledInSomePaths
                            ? "Lacked a call of 'super()' in some code paths."
                            : "Expected to call 'super()'.",
                        node: node.parent
                    });
                }
            },
 
            /**
             * Initialize information of a given code path segment.
             * @param {CodePathSegment} segment - A code path segment to initialize.
             * @returns {void}
             */
            onCodePathSegmentStart(segment) {
                if (!(funcInfo && funcInfo.isConstructor && funcInfo.hasExtends)) {
                    return;
                }
 
                // Initialize info.
                const info = segInfoMap[segment.id] = {
                    calledInSomePaths: false,
                    calledInEveryPaths: false,
                    validNodes: []
                };
 
                // When there are previous segments, aggregates these.
                const prevSegments = segment.prevSegments;
 
                if (prevSegments.length > 0) {
                    info.calledInSomePaths = prevSegments.some(isCalledInSomePath);
                    info.calledInEveryPaths = prevSegments.every(isCalledInEveryPath);
                }
            },
 
            /**
             * Update information of the code path segment when a code path was
             * looped.
             * @param {CodePathSegment} fromSegment - The code path segment of the
             *      end of a loop.
             * @param {CodePathSegment} toSegment - A code path segment of the head
             *      of a loop.
             * @returns {void}
             */
            onCodePathSegmentLoop(fromSegment, toSegment) {
                if (!(funcInfo && funcInfo.isConstructor && funcInfo.hasExtends)) {
                    return;
                }
 
                // Update information inside of the loop.
                const isRealLoop = toSegment.prevSegments.length >= 2;
 
                funcInfo.codePath.traverseSegments(
                    { first: toSegment, last: fromSegment },
                    segment => {
                        const info = segInfoMap[segment.id];
                        const prevSegments = segment.prevSegments;
 
                        // Updates flags.
                        info.calledInSomePaths = prevSegments.some(isCalledInSomePath);
                        info.calledInEveryPaths = prevSegments.every(isCalledInEveryPath);
 
                        // If flags become true anew, reports the valid nodes.
                        if (info.calledInSomePaths || isRealLoop) {
                            const nodes = info.validNodes;
 
                            info.validNodes = [];
 
                            for (let i = 0; i < nodes.length; ++i) {
                                const node = nodes[i];
 
                                context.report({
                                    message: "Unexpected duplicate 'super()'.",
                                    node
                                });
                            }
                        }
                    }
                );
            },
 
            /**
             * Checks for a call of `super()`.
             * @param {ASTNode} node - A CallExpression node to check.
             * @returns {void}
             */
            "CallExpression:exit"(node) {
                if (!(funcInfo && funcInfo.isConstructor)) {
                    return;
                }
 
                // Skips except `super()`.
                if (node.callee.type !== "Super") {
                    return;
                }
 
                // Reports if needed.
                if (funcInfo.hasExtends) {
                    const segments = funcInfo.codePath.currentSegments;
                    let duplicate = false;
                    let info = null;
 
                    for (let i = 0; i < segments.length; ++i) {
                        const segment = segments[i];
 
                        if (segment.reachable) {
                            info = segInfoMap[segment.id];
 
                            duplicate = duplicate || info.calledInSomePaths;
                            info.calledInSomePaths = info.calledInEveryPaths = true;
                        }
                    }
 
                    if (info) {
                        if (duplicate) {
                            context.report({
                                message: "Unexpected duplicate 'super()'.",
                                node
                            });
                        } else if (!funcInfo.superIsConstructor) {
                            context.report({
                                message: "Unexpected 'super()' because 'super' is not a constructor.",
                                node
                            });
                        } else {
                            info.validNodes.push(node);
                        }
                    }
                } else if (funcInfo.codePath.currentSegments.some(isReachable)) {
                    context.report({
                        message: "Unexpected 'super()'.",
                        node
                    });
                }
            },
 
            /**
             * Set the mark to the returned path as `super()` was called.
             * @param {ASTNode} node - A ReturnStatement node to check.
             * @returns {void}
             */
            ReturnStatement(node) {
                if (!(funcInfo && funcInfo.isConstructor && funcInfo.hasExtends)) {
                    return;
                }
 
                // Skips if no argument.
                if (!node.argument) {
                    return;
                }
 
                // Returning argument is a substitute of 'super()'.
                const segments = funcInfo.codePath.currentSegments;
 
                for (let i = 0; i < segments.length; ++i) {
                    const segment = segments[i];
 
                    if (segment.reachable) {
                        const info = segInfoMap[segment.id];
 
                        info.calledInSomePaths = info.calledInEveryPaths = true;
                    }
                }
            },
 
            /**
             * Resets state.
             * @returns {void}
             */
            "Program:exit"() {
                segInfoMap = Object.create(null);
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/curly.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/curly.js

Statements: 12.04% (13 / 108)      Branches: 0% (0 / 89)      Functions: 0% (0 / 19)      Lines: 12.04% (13 / 108)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398                    1 1           1                                                                                                                   1                           1                         1                 1                             1                                                     1                                   1                                                                                                               1                                                                                                         1                                                                                             1                                                                                                                                            
/**
 * @fileoverview Rule to flag statements without curly braces
 * @author Nicholas C. Zakas
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
const esUtils = require("esutils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent brace style for all control statements",
            category: "Best Practices",
            recommended: false
        },
 
        schema: {
            anyOf: [
                {
                    type: "array",
                    items: [
                        {
                            enum: ["all"]
                        }
                    ],
                    minItems: 0,
                    maxItems: 1
                },
                {
                    type: "array",
                    items: [
                        {
                            enum: ["multi", "multi-line", "multi-or-nest"]
                        },
                        {
                            enum: ["consistent"]
                        }
                    ],
                    minItems: 0,
                    maxItems: 2
                }
            ]
        },
 
        fixable: "code"
    },
 
    create(context) {
 
        const multiOnly = (context.options[0] === "multi");
        const multiLine = (context.options[0] === "multi-line");
        const multiOrNest = (context.options[0] === "multi-or-nest");
        const consistent = (context.options[1] === "consistent");
 
        const sourceCode = context.getSourceCode();
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Determines if a given node is a one-liner that's on the same line as it's preceding code.
         * @param {ASTNode} node The node to check.
         * @returns {boolean} True if the node is a one-liner that's on the same line as it's preceding code.
         * @private
         */
        function isCollapsedOneLiner(node) {
            const before = sourceCode.getTokenBefore(node);
            const last = sourceCode.getLastToken(node);
            const lastExcludingSemicolon = astUtils.isSemicolonToken(last) ? sourceCode.getTokenBefore(last) : last;
 
            return before.loc.start.line === lastExcludingSemicolon.loc.end.line;
        }
 
        /**
         * Determines if a given node is a one-liner.
         * @param {ASTNode} node The node to check.
         * @returns {boolean} True if the node is a one-liner.
         * @private
         */
        function isOneLiner(node) {
            const first = sourceCode.getFirstToken(node),
                last = sourceCode.getLastToken(node);
 
            return first.loc.start.line === last.loc.end.line;
        }
 
        /**
         * Checks if the given token is an `else` token or not.
         *
         * @param {Token} token - The token to check.
         * @returns {boolean} `true` if the token is an `else` token.
         */
        function isElseKeywordToken(token) {
            return token.value === "else" && token.type === "Keyword";
        }
 
        /**
         * Gets the `else` keyword token of a given `IfStatement` node.
         * @param {ASTNode} node - A `IfStatement` node to get.
         * @returns {Token} The `else` keyword token.
         */
        function getElseKeyword(node) {
            return node.alternate && sourceCode.getFirstTokenBetween(node.consequent, node.alternate, isElseKeywordToken);
        }
 
        /**
         * Checks a given IfStatement node requires braces of the consequent chunk.
         * This returns `true` when below:
         *
         * 1. The given node has the `alternate` node.
         * 2. There is a `IfStatement` which doesn't have `alternate` node in the
         *    trailing statement chain of the `consequent` node.
         *
         * @param {ASTNode} node - A IfStatement node to check.
         * @returns {boolean} `true` if the node requires braces of the consequent chunk.
         */
        function requiresBraceOfConsequent(node) {
            if (node.alternate && node.consequent.type === "BlockStatement") {
                if (node.consequent.body.length >= 2) {
                    return true;
                }
 
                node = node.consequent.body[0];
                while (node) {
                    if (node.type === "IfStatement" && !node.alternate) {
                        return true;
                    }
                    node = astUtils.getTrailingStatement(node);
                }
            }
 
            return false;
        }
 
        /**
         * Reports "Expected { after ..." error
         * @param {ASTNode} node The node to report.
         * @param {ASTNode} bodyNode The body node that is incorrectly missing curly brackets
         * @param {string} name The name to report.
         * @param {string} suffix Additional string to add to the end of a report.
         * @returns {void}
         * @private
         */
        function reportExpectedBraceError(node, bodyNode, name, suffix) {
            context.report({
                node,
                loc: (name !== "else" ? node : getElseKeyword(node)).loc.start,
                message: "Expected { after '{{name}}'{{suffix}}.",
                data: {
                    name,
                    suffix: (suffix ? ` ${suffix}` : "")
                },
                fix: fixer => fixer.replaceText(bodyNode, `{${sourceCode.getText(bodyNode)}}`)
            });
        }
 
        /**
        * Determines if a semicolon needs to be inserted after removing a set of curly brackets, in order to avoid a SyntaxError.
        * @param {Token} closingBracket The } token
        * @returns {boolean} `true` if a semicolon needs to be inserted after the last statement in the block.
        */
        function needsSemicolon(closingBracket) {
            const tokenBefore = sourceCode.getTokenBefore(closingBracket);
            const tokenAfter = sourceCode.getTokenAfter(closingBracket);
            const lastBlockNode = sourceCode.getNodeByRangeIndex(tokenBefore.range[0]);
 
            if (astUtils.isSemicolonToken(tokenBefore)) {
 
                // If the last statement already has a semicolon, don't add another one.
                return false;
            }
 
            if (!tokenAfter) {
 
                // If there are no statements after this block, there is no need to add a semicolon.
                return false;
            }
 
            if (lastBlockNode.type === "BlockStatement" && lastBlockNode.parent.type !== "FunctionExpression" && lastBlockNode.parent.type !== "ArrowFunctionExpression") {
 
                // If the last node surrounded by curly brackets is a BlockStatement (other than a FunctionExpression or an ArrowFunctionExpression),
                // don't insert a semicolon. Otherwise, the semicolon would be parsed as a separate statement, which would cause
                // a SyntaxError if it was followed by `else`.
                return false;
            }
 
            if (tokenBefore.loc.end.line === tokenAfter.loc.start.line) {
 
                // If the next token is on the same line, insert a semicolon.
                return true;
            }
 
            if (/^[([/`+-]/.test(tokenAfter.value)) {
 
                // If the next token starts with a character that would disrupt ASI, insert a semicolon.
                return true;
            }
 
            if (tokenBefore.type === "Punctuator" && (tokenBefore.value === "++" || tokenBefore.value === "--")) {
 
                // If the last token is ++ or --, insert a semicolon to avoid disrupting ASI.
                return true;
            }
 
            // Otherwise, do not insert a semicolon.
            return false;
        }
 
        /**
         * Reports "Unnecessary { after ..." error
         * @param {ASTNode} node The node to report.
         * @param {ASTNode} bodyNode The block statement that is incorrectly surrounded by parens
         * @param {string} name The name to report.
         * @param {string} suffix Additional string to add to the end of a report.
         * @returns {void}
         * @private
         */
        function reportUnnecessaryBraceError(node, bodyNode, name, suffix) {
            context.report({
                node,
                loc: (name !== "else" ? node : getElseKeyword(node)).loc.start,
                message: "Unnecessary { after '{{name}}'{{suffix}}.",
                data: {
                    name,
                    suffix: (suffix ? ` ${suffix}` : "")
                },
                fix(fixer) {
 
                    // `do while` expressions sometimes need a space to be inserted after `do`.
                    // e.g. `do{foo()} while (bar)` should be corrected to `do foo() while (bar)`
                    const needsPrecedingSpace = node.type === "DoWhileStatement" &&
                        sourceCode.getTokenBefore(bodyNode).end === bodyNode.start &&
                        esUtils.code.isIdentifierPartES6(sourceCode.getText(bodyNode).charCodeAt(1));
 
                    const openingBracket = sourceCode.getFirstToken(bodyNode);
                    const closingBracket = sourceCode.getLastToken(bodyNode);
                    const lastTokenInBlock = sourceCode.getTokenBefore(closingBracket);
 
                    if (needsSemicolon(closingBracket)) {
 
                        /*
                         * If removing braces would cause a SyntaxError due to multiple statements on the same line (or
                         * change the semantics of the code due to ASI), don't perform a fix.
                         */
                        return null;
                    }
 
                    const resultingBodyText = sourceCode.getText().slice(openingBracket.range[1], lastTokenInBlock.range[0]) +
                        sourceCode.getText(lastTokenInBlock) +
                        sourceCode.getText().slice(lastTokenInBlock.range[1], closingBracket.range[0]);
 
                    return fixer.replaceText(bodyNode, (needsPrecedingSpace ? " " : "") + resultingBodyText);
                }
            });
        }
 
        /**
         * Prepares to check the body of a node to see if it's a block statement.
         * @param {ASTNode} node The node to report if there's a problem.
         * @param {ASTNode} body The body node to check for blocks.
         * @param {string} name The name to report if there's a problem.
         * @param {string} suffix Additional string to add to the end of a report.
         * @returns {Object} a prepared check object, with "actual", "expected", "check" properties.
         *   "actual" will be `true` or `false` whether the body is already a block statement.
         *   "expected" will be `true` or `false` if the body should be a block statement or not, or
         *   `null` if it doesn't matter, depending on the rule options. It can be modified to change
         *   the final behavior of "check".
         *   "check" will be a function reporting appropriate problems depending on the other
         *   properties.
         */
        function prepareCheck(node, body, name, suffix) {
            const hasBlock = (body.type === "BlockStatement");
            let expected = null;
 
            if (node.type === "IfStatement" && node.consequent === body && requiresBraceOfConsequent(node)) {
                expected = true;
            } else if (multiOnly) {
                if (hasBlock && body.body.length === 1) {
                    expected = false;
                }
            } else if (multiLine) {
                if (!isCollapsedOneLiner(body)) {
                    expected = true;
                }
            } else if (multiOrNest) {
                if (hasBlock && body.body.length === 1 && isOneLiner(body.body[0])) {
                    const leadingComments = sourceCode.getComments(body.body[0]).leading;
 
                    expected = leadingComments.length > 0;
                } else if (!isOneLiner(body)) {
                    expected = true;
                }
            } else {
                expected = true;
            }
 
            return {
                actual: hasBlock,
                expected,
                check() {
                    if (this.expected !== null && this.expected !== this.actual) {
                        if (this.expected) {
                            reportExpectedBraceError(node, body, name, suffix);
                        } else {
                            reportUnnecessaryBraceError(node, body, name, suffix);
                        }
                    }
                }
            };
        }
 
        /**
         * Prepares to check the bodies of a "if", "else if" and "else" chain.
         * @param {ASTNode} node The first IfStatement node of the chain.
         * @returns {Object[]} prepared checks for each body of the chain. See `prepareCheck` for more
         *   information.
         */
        function prepareIfChecks(node) {
            const preparedChecks = [];
 
            do {
                preparedChecks.push(prepareCheck(node, node.consequent, "if", "condition"));
                if (node.alternate && node.alternate.type !== "IfStatement") {
                    preparedChecks.push(prepareCheck(node, node.alternate, "else"));
                    break;
                }
                node = node.alternate;
            } while (node);
 
            if (consistent) {
 
                /*
                 * If any node should have or already have braces, make sure they
                 * all have braces.
                 * If all nodes shouldn't have braces, make sure they don't.
                 */
                const expected = preparedChecks.some(preparedCheck => {
                    if (preparedCheck.expected !== null) {
                        return preparedCheck.expected;
                    }
                    return preparedCheck.actual;
                });
 
                preparedChecks.forEach(preparedCheck => {
                    preparedCheck.expected = expected;
                });
            }
 
            return preparedChecks;
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            IfStatement(node) {
                if (node.parent.type !== "IfStatement") {
                    prepareIfChecks(node).forEach(preparedCheck => {
                        preparedCheck.check();
                    });
                }
            },
 
            WhileStatement(node) {
                prepareCheck(node, node.body, "while", "condition").check();
            },
 
            DoWhileStatement(node) {
                prepareCheck(node, node.body, "do").check();
            },
 
            ForStatement(node) {
                prepareCheck(node, node.body, "for", "condition").check();
            },
 
            ForInStatement(node) {
                prepareCheck(node, node.body, "for-in").check();
            },
 
            ForOfStatement(node) {
                prepareCheck(node, node.body, "for-of").check();
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/default-case.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/default-case.js

Statements: 15% (3 / 20)      Branches: 0% (0 / 14)      Functions: 0% (0 / 3)      Lines: 15.79% (3 / 19)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92            1           1                                                                       1                                                                                      
/**
 * @fileoverview require default case in switch statements
 * @author Aliaksei Shytkin
 */
"use strict";
 
const DEFAULT_COMMENT_PATTERN = /^no default$/i;
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require `default` cases in `switch` statements",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [{
            type: "object",
            properties: {
                commentPattern: {
                    type: "string"
                }
            },
            additionalProperties: false
        }]
    },
 
    create(context) {
        const options = context.options[0] || {};
        const commentPattern = options.commentPattern
            ? new RegExp(options.commentPattern)
            : DEFAULT_COMMENT_PATTERN;
 
        const sourceCode = context.getSourceCode();
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Shortcut to get last element of array
         * @param  {*[]} collection Array
         * @returns {*} Last element
         */
        function last(collection) {
            return collection[collection.length - 1];
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
 
            SwitchStatement(node) {
 
                if (!node.cases.length) {
 
                    /*
                     * skip check of empty switch because there is no easy way
                     * to extract comments inside it now
                     */
                    return;
                }
 
                const hasDefault = node.cases.some(v => v.test === null);
 
                if (!hasDefault) {
 
                    let comment;
 
                    const lastCase = last(node.cases);
                    const comments = sourceCode.getComments(lastCase).trailing;
 
                    if (comments.length) {
                        comment = last(comments);
                    }
 
                    if (!comment || !commentPattern.test(comment.value.trim())) {
                        context.report({ node, message: "Expected a default case." });
                    }
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/dot-location.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/dot-location.js

Statements: 19.05% (4 / 21)      Branches: 0% (0 / 14)      Functions: 0% (0 / 3)      Lines: 19.05% (4 / 21)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90              1           1                                                                 1                                                                 1                    
/**
 * @fileoverview Validates newlines before and after dots
 * @author Greg Cochard
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent newlines before and after dots",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [
            {
                enum: ["object", "property"]
            }
        ],
 
        fixable: "code"
    },
 
    create(context) {
 
        const config = context.options[0];
 
        // default to onObject if no preference is passed
        const onObject = config === "object" || !config;
 
        const sourceCode = context.getSourceCode();
 
        /**
         * Reports if the dot between object and property is on the correct loccation.
         * @param {ASTNode} obj The object owning the property.
         * @param {ASTNode} prop The property of the object.
         * @param {ASTNode} node The corresponding node of the token.
         * @returns {void}
         */
        function checkDotLocation(obj, prop, node) {
            const dot = sourceCode.getTokenBefore(prop);
            const textBeforeDot = sourceCode.getText().slice(obj.range[1], dot.range[0]);
            const textAfterDot = sourceCode.getText().slice(dot.range[1], prop.range[0]);
 
            if (dot.type === "Punctuator" && dot.value === ".") {
                if (onObject) {
                    if (!astUtils.isTokenOnSameLine(obj, dot)) {
                        const neededTextAfterObj = astUtils.isDecimalInteger(obj) ? " " : "";
 
                        context.report({
                            node,
                            loc: dot.loc.start,
                            message: "Expected dot to be on same line as object.",
                            fix: fixer => fixer.replaceTextRange([obj.range[1], prop.range[0]], `${neededTextAfterObj}.${textBeforeDot}${textAfterDot}`)
                        });
                    }
                } else if (!astUtils.isTokenOnSameLine(dot, prop)) {
                    context.report({
                        node,
                        loc: dot.loc.start,
                        message: "Expected dot to be on same line as property.",
                        fix: fixer => fixer.replaceTextRange([obj.range[1], prop.range[0]], `${textBeforeDot}${textAfterDot}.`)
                    });
                }
            }
        }
 
        /**
         * Checks the spacing of the dot within a member expression.
         * @param {ASTNode} node The node to check.
         * @returns {void}
         */
        function checkNode(node) {
            checkDotLocation(node.object, node.property, node);
        }
 
        return {
            MemberExpression: checkNode
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/dot-notation.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/dot-notation.js

Statements: 14.81% (4 / 27)      Branches: 0% (0 / 28)      Functions: 0% (0 / 4)      Lines: 14.81% (4 / 27)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125                    1           1 1   1                                                                                                                                                                                                                  
/**
 * @fileoverview Rule to warn about using dot notation instead of square bracket notation when possible.
 * @author Josh Perez
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
const keywords = require("../util/keywords");
 
module.exports = {
    meta: {
        docs: {
            description: "enforce dot notation whenever possible",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    allowKeywords: {
                        type: "boolean"
                    },
                    allowPattern: {
                        type: "string"
                    }
                },
                additionalProperties: false
            }
        ],
 
        fixable: "code"
    },
 
    create(context) {
        const options = context.options[0] || {};
        const allowKeywords = options.allowKeywords === void 0 || !!options.allowKeywords;
        const sourceCode = context.getSourceCode();
 
        let allowPattern;
 
        if (options.allowPattern) {
            allowPattern = new RegExp(options.allowPattern);
        }
 
        return {
            MemberExpression(node) {
                if (
                    node.computed &&
                    node.property.type === "Literal" &&
                    validIdentifier.test(node.property.value) &&
                    (allowKeywords || keywords.indexOf(String(node.property.value)) === -1)
                ) {
                    if (!(allowPattern && allowPattern.test(node.property.value))) {
                        context.report({
                            node: node.property,
                            message: "[{{propertyValue}}] is better written in dot notation.",
                            data: {
                                propertyValue: JSON.stringify(node.property.value)
                            },
                            fix(fixer) {
                                const leftBracket = sourceCode.getTokenAfter(node.object, astUtils.isOpeningBracketToken);
                                const rightBracket = sourceCode.getLastToken(node);
 
                                if (sourceCode.getFirstTokenBetween(leftBracket, rightBracket, { includeComments: true, filter: astUtils.isCommentToken })) {
 
                                    // Don't perform any fixes if there are comments inside the brackets.
                                    return null;
                                }
 
                                const textBeforeDot = astUtils.isDecimalInteger(node.object) ? " " : "";
 
                                return fixer.replaceTextRange(
                                    [leftBracket.range[0], rightBracket.range[1]],
                                    `${textBeforeDot}.${node.property.value}`
                                );
                            }
                        });
                    }
                }
                if (
                    !allowKeywords &&
                    !node.computed &&
                    keywords.indexOf(String(node.property.name)) !== -1
                ) {
                    context.report({
                        node: node.property,
                        message: ".{{propertyName}} is a syntax error.",
                        data: {
                            propertyName: node.property.name
                        },
                        fix(fixer) {
                            const dot = sourceCode.getTokenBefore(node.property);
                            const textAfterDot = sourceCode.text.slice(dot.range[1], node.property.range[0]);
 
                            if (textAfterDot.trim()) {
 
                                // Don't perform any fixes if there are comments between the dot and the property name.
                                return null;
                            }
 
                            return fixer.replaceTextRange(
                                [dot.range[0], node.property.range[1]],
                                `[${textAfterDot}"${node.property.name}"]`
                            );
                        }
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/eol-last.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/eol-last.js

Statements: 11.76% (2 / 17)      Branches: 0% (0 / 16)      Functions: 0% (0 / 4)      Lines: 11.76% (2 / 17)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96                    1           1                                                                                                                                                              
/**
 * @fileoverview Require or disallow newline at the end of files
 * @author Nodeca Team <https://github.com/nodeca>
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const lodash = require("lodash");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require or disallow newline at the end of files",
            category: "Stylistic Issues",
            recommended: false
        },
        fixable: "whitespace",
        schema: [
            {
                enum: ["always", "never", "unix", "windows"]
            }
        ]
    },
    create(context) {
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            Program: function checkBadEOF(node) {
                const sourceCode = context.getSourceCode(),
                    src = sourceCode.getText(),
                    location = {
                        column: lodash.last(sourceCode.lines).length,
                        line: sourceCode.lines.length
                    },
                    LF = "\n",
                    CRLF = `\r${LF}`,
                    endsWithNewline = lodash.endsWith(src, LF);
 
                let mode = context.options[0] || "always",
                    appendCRLF = false;
 
                if (mode === "unix") {
 
                    // `"unix"` should behave exactly as `"always"`
                    mode = "always";
                }
                if (mode === "windows") {
 
                    // `"windows"` should behave exactly as `"always"`, but append CRLF in the fixer for backwards compatibility
                    mode = "always";
                    appendCRLF = true;
                }
                if (mode === "always" && !endsWithNewline) {
 
                    // File is not newline-terminated, but should be
                    context.report({
                        node,
                        loc: location,
                        message: "Newline required at end of file but not found.",
                        fix(fixer) {
                            return fixer.insertTextAfterRange([0, src.length], appendCRLF ? CRLF : LF);
                        }
                    });
                } else if (mode === "never" && endsWithNewline) {
 
                    // File is newline-terminated, but shouldn't be
                    context.report({
                        node,
                        loc: location,
                        message: "Newline not allowed at end of file.",
                        fix(fixer) {
                            const finalEOLs = /(?:\r?\n)+$/,
                                match = finalEOLs.exec(sourceCode.text),
                                start = match.index,
                                end = sourceCode.text.length;
 
                            return fixer.replaceTextRange([start, end], "");
                        }
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/eqeqeq.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/eqeqeq.js

Statements: 21.62% (8 / 37)      Branches: 0% (0 / 39)      Functions: 0% (0 / 9)      Lines: 21.62% (8 / 37)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182                      1           1                                                                                                                     1                   1                   1                     1                     1                         1                                                                                                    
/**
 * @fileoverview Rule to flag statements that use != and == instead of !== and ===
 * @author Nicholas C. Zakas
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require the use of `===` and `!==`",
            category: "Best Practices",
            recommended: false
        },
 
        schema: {
            anyOf: [
                {
                    type: "array",
                    items: [
                        {
                            enum: ["always"]
                        },
                        {
                            type: "object",
                            properties: {
                                null: {
                                    enum: ["always", "never", "ignore"]
                                }
                            },
                            additionalProperties: false
                        }
                    ],
                    additionalItems: false
                },
                {
                    type: "array",
                    items: [
                        {
                            enum: ["smart", "allow-null"]
                        }
                    ],
                    additionalItems: false
                }
            ]
        },
 
        fixable: "code"
    },
 
    create(context) {
        const config = context.options[0] || "always";
        const options = context.options[1] || {};
        const sourceCode = context.getSourceCode();
 
        const nullOption = (config === "always")
            ? options.null || "always"
            : "ignore";
        const enforceRuleForNull = (nullOption === "always");
        const enforceInverseRuleForNull = (nullOption === "never");
 
        /**
         * Checks if an expression is a typeof expression
         * @param  {ASTNode} node The node to check
         * @returns {boolean} if the node is a typeof expression
         */
        function isTypeOf(node) {
            return node.type === "UnaryExpression" && node.operator === "typeof";
        }
 
        /**
         * Checks if either operand of a binary expression is a typeof operation
         * @param {ASTNode} node The node to check
         * @returns {boolean} if one of the operands is typeof
         * @private
         */
        function isTypeOfBinary(node) {
            return isTypeOf(node.left) || isTypeOf(node.right);
        }
 
        /**
         * Checks if operands are literals of the same type (via typeof)
         * @param {ASTNode} node The node to check
         * @returns {boolean} if operands are of same type
         * @private
         */
        function areLiteralsAndSameType(node) {
            return node.left.type === "Literal" && node.right.type === "Literal" &&
                    typeof node.left.value === typeof node.right.value;
        }
 
        /**
         * Checks if one of the operands is a literal null
         * @param {ASTNode} node The node to check
         * @returns {boolean} if operands are null
         * @private
         */
        function isNullCheck(node) {
            return astUtils.isNullLiteral(node.right) || astUtils.isNullLiteral(node.left);
        }
 
        /**
         * Gets the location (line and column) of the binary expression's operator
         * @param {ASTNode} node The binary expression node to check
         * @param {string} operator The operator to find
         * @returns {Object} { line, column } location of operator
         * @private
         */
        function getOperatorLocation(node) {
            const opToken = sourceCode.getTokenAfter(node.left);
 
            return { line: opToken.loc.start.line, column: opToken.loc.start.column };
        }
 
        /**
         * Reports a message for this rule.
         * @param {ASTNode} node The binary expression node that was checked
         * @param {string} expectedOperator The operator that was expected (either '==', '!=', '===', or '!==')
         * @returns {void}
         * @private
         */
        function report(node, expectedOperator) {
            context.report({
                node,
                loc: getOperatorLocation(node),
                message: "Expected '{{expectedOperator}}' and instead saw '{{actualOperator}}'.",
                data: { expectedOperator, actualOperator: node.operator },
                fix(fixer) {
 
                    // If the comparison is a `typeof` comparison or both sides are literals with the same type, then it's safe to fix.
                    if (isTypeOfBinary(node) || areLiteralsAndSameType(node)) {
                        const operatorToken = sourceCode.getFirstTokenBetween(
                            node.left,
                            node.right,
                            token => token.value === node.operator
                        );
 
                        return fixer.replaceText(operatorToken, expectedOperator);
                    }
                    return null;
                }
            });
        }
 
        return {
            BinaryExpression(node) {
                const isNull = isNullCheck(node);
 
                if (node.operator !== "==" && node.operator !== "!=") {
                    if (enforceInverseRuleForNull && isNull) {
                        report(node, node.operator.slice(0, -1));
                    }
                    return;
                }
 
                if (config === "smart" && (isTypeOfBinary(node) ||
                        areLiteralsAndSameType(node) || isNull)) {
                    return;
                }
 
                if (!enforceRuleForNull && isNull) {
                    return;
                }
 
                report(node, `${node.operator}=`);
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/func-call-spacing.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/func-call-spacing.js

Statements: 10.71% (3 / 28)      Branches: 0% (0 / 26)      Functions: 0% (0 / 5)      Lines: 10.71% (3 / 28)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159                      1           1                                                                                                                 1                                                                                                                                                                        
/**
 * @fileoverview Rule to control spacing within function calls
 * @author Matt DuVall <http://www.mattduvall.com>
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require or disallow spacing between function identifiers and their invocations",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
        schema: {
            anyOf: [
                {
                    type: "array",
                    items: [
                        {
                            enum: ["never"]
                        }
                    ],
                    minItems: 0,
                    maxItems: 1
                },
                {
                    type: "array",
                    items: [
                        {
                            enum: ["always"]
                        },
                        {
                            type: "object",
                            properties: {
                                allowNewlines: {
                                    type: "boolean"
                                }
                            },
                            additionalProperties: false
                        }
                    ],
                    minItems: 0,
                    maxItems: 2
                }
            ]
        }
    },
 
    create(context) {
 
        const never = context.options[0] !== "always";
        const allowNewlines = !never && context.options[1] && context.options[1].allowNewlines;
        const sourceCode = context.getSourceCode();
        const text = sourceCode.getText();
 
        /**
         * Check if open space is present in a function name
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function checkSpacing(node) {
            const lastToken = sourceCode.getLastToken(node);
            const lastCalleeToken = sourceCode.getLastToken(node.callee);
            const parenToken = sourceCode.getFirstTokenBetween(lastCalleeToken, lastToken, astUtils.isOpeningParenToken);
            const prevToken = parenToken && sourceCode.getTokenBefore(parenToken);
 
            // Parens in NewExpression are optional
            if (!(parenToken && parenToken.range[1] < node.range[1])) {
                return;
            }
 
            const textBetweenTokens = text.slice(prevToken.range[1], parenToken.range[0]).replace(/\/\*.*?\*\//g, "");
            const hasWhitespace = /\s/.test(textBetweenTokens);
            const hasNewline = hasWhitespace && astUtils.LINEBREAK_MATCHER.test(textBetweenTokens);
 
            /*
             * never allowNewlines hasWhitespace hasNewline message
             * F     F             F             F          Missing space between function name and paren.
             * F     F             F             T          (Invalid `!hasWhitespace && hasNewline`)
             * F     F             T             T          Unexpected newline between function name and paren.
             * F     F             T             F          (OK)
             * F     T             T             F          (OK)
             * F     T             T             T          (OK)
             * F     T             F             T          (Invalid `!hasWhitespace && hasNewline`)
             * F     T             F             F          Missing space between function name and paren.
             * T     T             F             F          (Invalid `never && allowNewlines`)
             * T     T             F             T          (Invalid `!hasWhitespace && hasNewline`)
             * T     T             T             T          (Invalid `never && allowNewlines`)
             * T     T             T             F          (Invalid `never && allowNewlines`)
             * T     F             T             F          Unexpected space between function name and paren.
             * T     F             T             T          Unexpected space between function name and paren.
             * T     F             F             T          (Invalid `!hasWhitespace && hasNewline`)
             * T     F             F             F          (OK)
             *
             * T                   T                        Unexpected space between function name and paren.
             * F                   F                        Missing space between function name and paren.
             * F     F                           T          Unexpected newline between function name and paren.
             */
 
            if (never && hasWhitespace) {
                context.report({
                    node,
                    loc: lastCalleeToken.loc.start,
                    message: "Unexpected space between function name and paren.",
                    fix(fixer) {
 
                        // Only autofix if there is no newline
                        // https://github.com/eslint/eslint/issues/7787
                        if (!hasNewline) {
                            return fixer.removeRange([prevToken.range[1], parenToken.range[0]]);
                        }
 
                        return null;
                    }
                });
            } else if (!never && !hasWhitespace) {
                context.report({
                    node,
                    loc: lastCalleeToken.loc.start,
                    message: "Missing space between function name and paren.",
                    fix(fixer) {
                        return fixer.insertTextBefore(parenToken, " ");
                    }
                });
            } else if (!never && !allowNewlines && hasNewline) {
                context.report({
                    node,
                    loc: lastCalleeToken.loc.start,
                    message: "Unexpected newline between function name and paren.",
                    fix(fixer) {
                        return fixer.replaceTextRange([prevToken.range[1], parenToken.range[0]], " ");
                    }
                });
            }
        }
 
        return {
            CallExpression: checkSpacing,
            NewExpression: checkSpacing
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/func-name-matching.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/func-name-matching.js

Statements: 19.61% (10 / 51)      Branches: 0% (0 / 79)      Functions: 0% (0 / 9)      Lines: 19.61% (10 / 51)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195                      1 1                     1                                           1                     1 1                   1                                                                 1                       1                                                     1                                                                                                              
/**
 * @fileoverview Rule to require function names to match the name of the variable or property to which they are assigned.
 * @author Annie Zhang, Pavel Strashkin
 */
 
"use strict";
 
//--------------------------------------------------------------------------
// Requirements
//--------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
const esutils = require("esutils");
 
//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------
 
/**
 * Determines if a pattern is `module.exports` or `module["exports"]`
 * @param {ASTNode} pattern The left side of the AssignmentExpression
 * @returns {boolean} True if the pattern is `module.exports` or `module["exports"]`
 */
function isModuleExports(pattern) {
    if (pattern.type === "MemberExpression" && pattern.object.type === "Identifier" && pattern.object.name === "module") {
 
        // module.exports
        if (pattern.property.type === "Identifier" && pattern.property.name === "exports") {
            return true;
        }
 
        // module["exports"]
        if (pattern.property.type === "Literal" && pattern.property.value === "exports") {
            return true;
        }
    }
    return false;
}
 
/**
 * Determines if a string name is a valid identifier
 * @param {string} name The string to be checked
 * @param {int} ecmaVersion The ECMAScript version if specified in the parserOptions config
 * @returns {boolean} True if the string is a valid identifier
 */
function isIdentifier(name, ecmaVersion) {
    if (ecmaVersion >= 6) {
        return esutils.keyword.isIdentifierES6(name);
    }
    return esutils.keyword.isIdentifierES5(name);
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
const alwaysOrNever = { enum: ["always", "never"] };
const optionsObject = {
    type: "object",
    properties: {
        includeCommonJSModuleExports: {
            type: "boolean"
        }
    },
    additionalProperties: false
};
 
module.exports = {
    meta: {
        docs: {
            description: "require function names to match the name of the variable or property to which they are assigned",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: {
            anyOf: [{
                type: "array",
                additionalItems: false,
                items: [alwaysOrNever, optionsObject]
            }, {
                type: "array",
                additionalItems: false,
                items: [optionsObject]
            }]
        }
    },
 
    create(context) {
        const options = (typeof context.options[0] === "object" ? context.options[0] : context.options[1]) || {};
        const nameMatches = typeof context.options[0] === "string" ? context.options[0] : "always";
        const includeModuleExports = options.includeCommonJSModuleExports;
        const ecmaVersion = context.parserOptions && context.parserOptions.ecmaVersion ? context.parserOptions.ecmaVersion : 5;
 
        /**
         * Compares identifiers based on the nameMatches option
         * @param {string} x the first identifier
         * @param {string} y the second identifier
         * @returns {boolean} whether the two identifiers should warn.
         */
        function shouldWarn(x, y) {
            return (nameMatches === "always" && x !== y) || (nameMatches === "never" && x === y);
        }
 
        /**
         * Reports
         * @param {ASTNode} node The node to report
         * @param {string} name The variable or property name
         * @param {string} funcName The function name
         * @param {boolean} isProp True if the reported node is a property assignment
         * @returns {void}
         */
        function report(node, name, funcName, isProp) {
            let message;
 
            if (nameMatches === "always" && isProp) {
                message = "Function name `{{funcName}}` should match property name `{{name}}`";
            } else if (nameMatches === "always") {
                message = "Function name `{{funcName}}` should match variable name `{{name}}`";
            } else if (isProp) {
                message = "Function name `{{funcName}}` should not match property name `{{name}}`";
            } else {
                message = "Function name `{{funcName}}` should not match variable name `{{name}}`";
            }
            context.report({
                node,
                message,
                data: {
                    name,
                    funcName
                }
            });
        }
 
        /**
         * Determines whether a given node is a string literal
         * @param {ASTNode} node The node to check
         * @returns {boolean} `true` if the node is a string literal
         */
        function isStringLiteral(node) {
            return node.type === "Literal" && typeof node.value === "string";
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
 
            VariableDeclarator(node) {
                if (!node.init || node.init.type !== "FunctionExpression" || node.id.type !== "Identifier") {
                    return;
                }
                if (node.init.id && shouldWarn(node.id.name, node.init.id.name)) {
                    report(node, node.id.name, node.init.id.name, false);
                }
            },
 
            AssignmentExpression(node) {
                if (
                    node.right.type !== "FunctionExpression" ||
                    (node.left.computed && node.left.property.type !== "Literal") ||
                    (!includeModuleExports && isModuleExports(node.left)) ||
                    (node.left.type !== "Identifier" && node.left.type !== "MemberExpression")
                ) {
                    return;
                }
 
                const isProp = node.left.type === "MemberExpression";
                const name = isProp ? astUtils.getStaticPropertyName(node.left) : node.left.name;
 
                if (node.right.id && isIdentifier(name) && shouldWarn(name, node.right.id.name)) {
                    report(node, name, node.right.id.name, isProp);
                }
            },
 
            Property(node) {
                if (node.value.type !== "FunctionExpression" || !node.value.id || node.computed && !isStringLiteral(node.key)) {
                    return;
                }
                if (node.key.type === "Identifier" && shouldWarn(node.key.name, node.value.id.name)) {
                    report(node, node.key.name, node.value.id.name, true);
                } else if (
                    isStringLiteral(node.key) &&
                    isIdentifier(node.key.value, ecmaVersion) &&
                    shouldWarn(node.key.value, node.value.id.name)
                ) {
                    report(node, node.key.value, node.value.id.name, true);
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/func-names.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/func-names.js

Statements: 21.74% (5 / 23)      Branches: 0% (0 / 36)      Functions: 0% (0 / 5)      Lines: 21.74% (5 / 23)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116                      1             1               1                                                 1                                   1                                                                                            
/**
 * @fileoverview Rule to warn when a function expression does not have a name.
 * @author Kyle T. Nunery
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
/**
 * Checks whether or not a given variable is a function name.
 * @param {escope.Variable} variable - A variable to check.
 * @returns {boolean} `true` if the variable is a function name.
 */
function isFunctionName(variable) {
    return variable && variable.defs[0].type === "FunctionName";
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require or disallow named `function` expressions",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                enum: ["always", "as-needed", "never"]
            }
        ]
    },
 
    create(context) {
        const never = context.options[0] === "never";
        const asNeeded = context.options[0] === "as-needed";
 
        /**
         * Determines whether the current FunctionExpression node is a get, set, or
         * shorthand method in an object literal or a class.
         * @param {ASTNode} node - A node to check.
         * @returns {boolean} True if the node is a get, set, or shorthand method.
         */
        function isObjectOrClassMethod(node) {
            const parent = node.parent;
 
            return (parent.type === "MethodDefinition" || (
                parent.type === "Property" && (
                    parent.method ||
                    parent.kind === "get" ||
                    parent.kind === "set"
                )
            ));
        }
 
        /**
         * Determines whether the current FunctionExpression node has a name that would be
         * inferred from context in a conforming ES6 environment.
         * @param {ASTNode} node - A node to check.
         * @returns {boolean} True if the node would have a name assigned automatically.
         */
        function hasInferredName(node) {
            const parent = node.parent;
 
            return isObjectOrClassMethod(node) ||
                (parent.type === "VariableDeclarator" && parent.id.type === "Identifier" && parent.init === node) ||
                (parent.type === "Property" && parent.value === node) ||
                (parent.type === "AssignmentExpression" && parent.left.type === "Identifier" && parent.right === node) ||
                (parent.type === "ExportDefaultDeclaration" && parent.declaration === node) ||
                (parent.type === "AssignmentPattern" && parent.right === node);
        }
 
        return {
            "FunctionExpression:exit"(node) {
 
                // Skip recursive functions.
                const nameVar = context.getDeclaredVariables(node)[0];
 
                if (isFunctionName(nameVar) && nameVar.references.length > 0) {
                    return;
                }
 
                const hasName = Boolean(node.id && node.id.name);
                const name = astUtils.getFunctionNameWithKind(node);
 
                if (never) {
                    if (hasName) {
                        context.report({
                            node,
                            message: "Unexpected named {{name}}.",
                            data: { name }
                        });
                    }
                } else {
                    if (!hasName && (asNeeded ? !hasInferredName(node) : !isObjectOrClassMethod(node))) {
                        context.report({
                            node,
                            message: "Unexpected unnamed {{name}}.",
                            data: { name }
                        });
                    }
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/func-style.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/func-style.js

Statements: 4.76% (1 / 21)      Branches: 0% (0 / 19)      Functions: 0% (0 / 8)      Lines: 4.76% (1 / 21)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91                    1                                                                                                                                                                
/**
 * @fileoverview Rule to enforce a particular function style
 * @author Nicholas C. Zakas
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce the consistent use of either `function` declarations or expressions",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                enum: ["declaration", "expression"]
            },
            {
                type: "object",
                properties: {
                    allowArrowFunctions: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        const style = context.options[0],
            allowArrowFunctions = context.options[1] && context.options[1].allowArrowFunctions === true,
            enforceDeclarations = (style === "declaration"),
            stack = [];
 
        const nodesToCheck = {
            FunctionDeclaration(node) {
                stack.push(false);
 
                if (!enforceDeclarations && node.parent.type !== "ExportDefaultDeclaration") {
                    context.report({ node, message: "Expected a function expression." });
                }
            },
            "FunctionDeclaration:exit"() {
                stack.pop();
            },
 
            FunctionExpression(node) {
                stack.push(false);
 
                if (enforceDeclarations && node.parent.type === "VariableDeclarator") {
                    context.report({ node: node.parent, message: "Expected a function declaration." });
                }
            },
            "FunctionExpression:exit"() {
                stack.pop();
            },
 
            ThisExpression() {
                if (stack.length > 0) {
                    stack[stack.length - 1] = true;
                }
            }
        };
 
        if (!allowArrowFunctions) {
            nodesToCheck.ArrowFunctionExpression = function() {
                stack.push(false);
            };
 
            nodesToCheck["ArrowFunctionExpression:exit"] = function(node) {
                const hasThisExpr = stack.pop();
 
                if (enforceDeclarations && !hasThisExpr && node.parent.type === "VariableDeclarator") {
                    context.report({ node: node.parent, message: "Expected a function declaration." });
                }
            };
        }
 
        return nodesToCheck;
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/generator-star-spacing.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/generator-star-spacing.js

Statements: 14.71% (5 / 34)      Branches: 0% (0 / 28)      Functions: 0% (0 / 7)      Lines: 14.71% (5 / 34)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150                      1                                                                                                     1                   1                               1                                                                   1                                                      
/**
 * @fileoverview Rule to check the spacing around the * in generator functions.
 * @author Jamund Ferguson
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent spacing around `*` operators in generator functions",
            category: "ECMAScript 6",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                oneOf: [
                    {
                        enum: ["before", "after", "both", "neither"]
                    },
                    {
                        type: "object",
                        properties: {
                            before: { type: "boolean" },
                            after: { type: "boolean" }
                        },
                        additionalProperties: false
                    }
                ]
            }
        ]
    },
 
    create(context) {
 
        const mode = (function(option) {
            if (!option || typeof option === "string") {
                return {
                    before: { before: true, after: false },
                    after: { before: false, after: true },
                    both: { before: true, after: true },
                    neither: { before: false, after: false }
                }[option || "before"];
            }
            return option;
        }(context.options[0]));
 
        const sourceCode = context.getSourceCode();
 
        /**
         * Checks if the given token is a star token or not.
         *
         * @param {Token} token - The token to check.
         * @returns {boolean} `true` if the token is a star token.
         */
        function isStarToken(token) {
            return token.value === "*" && token.type === "Punctuator";
        }
 
        /**
         * Gets the generator star token of the given function node.
         *
         * @param {ASTNode} node - The function node to get.
         * @returns {Token} Found star token.
         */
        function getStarToken(node) {
            return sourceCode.getFirstToken(
                (node.parent.method || node.parent.type === "MethodDefinition") ? node.parent : node,
                isStarToken
            );
        }
 
        /**
         * Checks the spacing between two tokens before or after the star token.
         * @param {string} side Either "before" or "after".
         * @param {Token} leftToken `function` keyword token if side is "before", or
         *     star token if side is "after".
         * @param {Token} rightToken Star token if side is "before", or identifier
         *     token if side is "after".
         * @returns {void}
         */
        function checkSpacing(side, leftToken, rightToken) {
            if (!!(rightToken.range[0] - leftToken.range[1]) !== mode[side]) {
                const after = leftToken.value === "*";
                const spaceRequired = mode[side];
                const node = after ? leftToken : rightToken;
                const type = spaceRequired ? "Missing" : "Unexpected";
                const message = "{{type}} space {{side}} *.";
                const data = {
                    type,
                    side
                };
 
                context.report({
                    node,
                    message,
                    data,
                    fix(fixer) {
                        if (spaceRequired) {
                            if (after) {
                                return fixer.insertTextAfter(node, " ");
                            }
                            return fixer.insertTextBefore(node, " ");
                        }
                        return fixer.removeRange([leftToken.range[1], rightToken.range[0]]);
                    }
                });
            }
        }
 
        /**
         * Enforces the spacing around the star if node is a generator function.
         * @param {ASTNode} node A function expression or declaration node.
         * @returns {void}
         */
        function checkFunction(node) {
            if (!node.generator) {
                return;
            }
 
            const starToken = getStarToken(node);
 
            // Only check before when preceded by `function`|`static` keyword
            const prevToken = sourceCode.getTokenBefore(starToken);
 
            if (prevToken.value === "function" || prevToken.value === "static") {
                checkSpacing("before", prevToken, starToken);
            }
 
            const nextToken = sourceCode.getTokenAfter(starToken);
 
            checkSpacing("after", starToken, nextToken);
        }
 
        return {
            FunctionDeclaration: checkFunction,
            FunctionExpression: checkFunction
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/global-require.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/global-require.js

Statements: 22.22% (4 / 18)      Branches: 7.69% (1 / 13)      Functions: 0% (0 / 4)      Lines: 25% (4 / 16)      Ignored: 1 branch     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77              1                                 1                                   1           1                                                        
/**
 * @fileoverview Rule for disallowing require() outside of the top-level module context
 * @author Jamund Ferguson
 */
 
"use strict";
 
const ACCEPTABLE_PARENTS = [
    "AssignmentExpression",
    "VariableDeclarator",
    "MemberExpression",
    "ExpressionStatement",
    "CallExpression",
    "ConditionalExpression",
    "Program",
    "VariableDeclaration"
];
 
/**
 * Finds the escope reference in the given scope.
 * @param {Object} scope The scope to search.
 * @param {ASTNode} node The identifier node.
 * @returns {Reference|null} Returns the found reference or null if none were found.
 */
function findReference(scope, node) {
    const references = scope.references.filter(reference => reference.identifier.range[0] === node.range[0] &&
            reference.identifier.range[1] === node.range[1]);
 
    /* istanbul ignore else: correctly returns null */
    if (references.length === 1) {
        return references[0];
    }
    return null;
 
}
 
/**
 * Checks if the given identifier node is shadowed in the given scope.
 * @param {Object} scope The current scope.
 * @param {ASTNode} node The identifier node to check.
 * @returns {boolean} Whether or not the name is shadowed.
 */
function isShadowed(scope, node) {
    const reference = findReference(scope, node);
 
    return reference && reference.resolved && reference.resolved.defs.length > 0;
}
 
module.exports = {
    meta: {
        docs: {
            description: "require `require()` calls to be placed at top-level module scope",
            category: "Node.js and CommonJS",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
        return {
            CallExpression(node) {
                const currentScope = context.getScope();
 
                if (node.callee.name === "require" && !isShadowed(currentScope, node.callee)) {
                    const isGoodRequire = context.getAncestors().every(parent => ACCEPTABLE_PARENTS.indexOf(parent.type) > -1);
 
                    if (!isGoodRequire) {
                        context.report({ node, message: "Unexpected require()." });
                    }
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/guard-for-in.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/guard-for-in.js

Statements: 20% (1 / 5)      Branches: 0% (0 / 6)      Functions: 0% (0 / 2)      Lines: 20% (1 / 5)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44                      1                                                                
/**
 * @fileoverview Rule to flag for-in loops without if statements inside
 * @author Nicholas C. Zakas
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require `for-in` loops to include an `if` statement",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
 
            ForInStatement(node) {
 
                /*
                 * If the for-in statement has {}, then the real body is the body
                 * of the BlockStatement. Otherwise, just use body as provided.
                 */
                const body = node.body.type === "BlockStatement" ? node.body.body[0] : node.body;
 
                if (body && body.type !== "IfStatement") {
                    context.report({ node, message: "The body of a for-in should be wrapped in an if statement to filter unwanted properties from the prototype." });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/handle-callback-err.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/handle-callback-err.js

Statements: 26.32% (5 / 19)      Branches: 0% (0 / 12)      Functions: 0% (0 / 5)      Lines: 27.78% (5 / 18)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91                      1                                               1                     1                           1                 1                                          
/**
 * @fileoverview Ensure handling of errors when we know they exist.
 * @author Jamund Ferguson
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require error handling in callbacks",
            category: "Node.js and CommonJS",
            recommended: false
        },
 
        schema: [
            {
                type: "string"
            }
        ]
    },
 
    create(context) {
 
        const errorArgument = context.options[0] || "err";
 
        /**
         * Checks if the given argument should be interpreted as a regexp pattern.
         * @param {string} stringToCheck The string which should be checked.
         * @returns {boolean} Whether or not the string should be interpreted as a pattern.
         */
        function isPattern(stringToCheck) {
            const firstChar = stringToCheck[0];
 
            return firstChar === "^";
        }
 
        /**
         * Checks if the given name matches the configured error argument.
         * @param {string} name The name which should be compared.
         * @returns {boolean} Whether or not the given name matches the configured error variable name.
         */
        function matchesConfiguredErrorName(name) {
            if (isPattern(errorArgument)) {
                const regexp = new RegExp(errorArgument);
 
                return regexp.test(name);
            }
            return name === errorArgument;
        }
 
        /**
         * Get the parameters of a given function scope.
         * @param {Object} scope The function scope.
         * @returns {array} All parameters of the given scope.
         */
        function getParameters(scope) {
            return scope.variables.filter(variable => variable.defs[0] && variable.defs[0].type === "Parameter");
        }
 
        /**
         * Check to see if we're handling the error object properly.
         * @param {ASTNode} node The AST node to check.
         * @returns {void}
         */
        function checkForError(node) {
            const scope = context.getScope(),
                parameters = getParameters(scope),
                firstParameter = parameters[0];
 
            if (firstParameter && matchesConfiguredErrorName(firstParameter.name)) {
                if (firstParameter.references.length === 0) {
                    context.report({ node, message: "Expected error to be handled." });
                }
            }
        }
 
        return {
            FunctionDeclaration: checkForError,
            FunctionExpression: checkForError,
            ArrowFunctionExpression: checkForError
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/id-blacklist.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/id-blacklist.js

Statements: 18.18% (4 / 22)      Branches: 0% (0 / 27)      Functions: 0% (0 / 5)      Lines: 18.18% (4 / 22)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119                        1                                                                 1                     1                       1                                                                                                    
/**
 * @fileoverview Rule that warns when identifier names that are
 * blacklisted in the configuration are used.
 * @author Keith Cirkel (http://keithcirkel.co.uk)
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow specified identifiers",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: {
            type: "array",
            items: {
                type: "string"
            },
            uniqueItems: true
        }
    },
 
    create(context) {
 
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        const blacklist = context.options;
 
 
        /**
         * Checks if a string matches the provided pattern
         * @param {string} name The string to check.
         * @returns {boolean} if the string is a match
         * @private
         */
        function isInvalid(name) {
            return blacklist.indexOf(name) !== -1;
        }
 
        /**
         * Verifies if we should report an error or not based on the effective
         * parent node and the identifier name.
         * @param {ASTNode} effectiveParent The effective parent node of the node to be reported
         * @param {string} name The identifier name of the identifier node
         * @returns {boolean} whether an error should be reported or not
         */
        function shouldReport(effectiveParent, name) {
            return effectiveParent.type !== "CallExpression" &&
                effectiveParent.type !== "NewExpression" &&
                isInvalid(name);
        }
 
        /**
         * Reports an AST node as a rule violation.
         * @param {ASTNode} node The node to report.
         * @returns {void}
         * @private
         */
        function report(node) {
            context.report({ node, message: "Identifier '{{name}}' is blacklisted.", data: {
                name: node.name
            } });
        }
 
        return {
 
            Identifier(node) {
                const name = node.name,
                    effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent;
 
                // MemberExpressions get special rules
                if (node.parent.type === "MemberExpression") {
 
                    // Always check object names
                    if (node.parent.object.type === "Identifier" &&
                        node.parent.object.name === node.name) {
                        if (isInvalid(name)) {
                            report(node);
                        }
 
                        // Report AssignmentExpressions only if they are the left side of the assignment
                    } else if (effectiveParent.type === "AssignmentExpression" &&
                        (effectiveParent.right.type !== "MemberExpression" ||
                        effectiveParent.left.type === "MemberExpression" &&
                        effectiveParent.left.property.name === node.name)) {
                        if (isInvalid(name)) {
                            report(node);
                        }
                    }
 
                // Properties have their own rules
                } else if (node.parent.type === "Property") {
 
                    if (shouldReport(effectiveParent, name)) {
                        report(node);
                    }
 
                // Report anything that is a match and not a CallExpression
                } else if (shouldReport(effectiveParent, name)) {
                    report(node);
                }
            }
 
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/id-length.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/id-length.js

Statements: 4.35% (1 / 23)      Branches: 0% (0 / 32)      Functions: 0% (0 / 6)      Lines: 4.35% (1 / 23)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118                        1                                                                                                                                                                                                                  
/**
 * @fileoverview Rule that warns when identifier names are shorter or longer
 * than the values provided in configuration.
 * @author Burak Yigit Kaya aka BYK
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce minimum and maximum identifier lengths",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    min: {
                        type: "number"
                    },
                    max: {
                        type: "number"
                    },
                    exceptions: {
                        type: "array",
                        uniqueItems: true,
                        items: {
                            type: "string"
                        }
                    },
                    properties: {
                        enum: ["always", "never"]
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const options = context.options[0] || {};
        const minLength = typeof options.min !== "undefined" ? options.min : 2;
        const maxLength = typeof options.max !== "undefined" ? options.max : Infinity;
        const properties = options.properties !== "never";
        const exceptions = (options.exceptions ? options.exceptions : [])
            .reduce((obj, item) => {
                obj[item] = true;
 
                return obj;
            }, {});
 
        const SUPPORTED_EXPRESSIONS = {
            MemberExpression: properties && function(parent) {
                return !parent.computed && (
 
                    // regular property assignment
                    (parent.parent.left === parent && parent.parent.type === "AssignmentExpression" ||
 
                    // or the last identifier in an ObjectPattern destructuring
                    parent.parent.type === "Property" && parent.parent.value === parent &&
                    parent.parent.parent.type === "ObjectPattern" && parent.parent.parent.parent.left === parent.parent.parent)
                );
            },
            AssignmentPattern(parent, node) {
                return parent.left === node;
            },
            VariableDeclarator(parent, node) {
                return parent.id === node;
            },
            Property: properties && function(parent, node) {
                return parent.key === node;
            },
            ImportDefaultSpecifier: true,
            RestElement: true,
            FunctionExpression: true,
            ArrowFunctionExpression: true,
            ClassDeclaration: true,
            FunctionDeclaration: true,
            MethodDefinition: true,
            CatchClause: true
        };
 
        return {
            Identifier(node) {
                const name = node.name;
                const parent = node.parent;
 
                const isShort = name.length < minLength;
                const isLong = name.length > maxLength;
 
                if (!(isShort || isLong) || exceptions[name]) {
                    return;  // Nothing to report
                }
 
                const isValidExpression = SUPPORTED_EXPRESSIONS[parent.type];
 
                if (isValidExpression && (isValidExpression === true || isValidExpression(parent, node))) {
                    context.report({
                        node,
                        message: isShort
                            ? "Identifier name '{{name}}' is too short (< {{min}})."
                            : "Identifier name '{{name}}' is too long (> {{max}}).",
                        data: { name, min: minLength, max: maxLength }
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/id-match.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/id-match.js

Statements: 13.33% (4 / 30)      Branches: 0% (0 / 43)      Functions: 0% (0 / 5)      Lines: 13.33% (4 / 30)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142                      1                                                                                   1                     1                       1                                                                                                                                  
/**
 * @fileoverview Rule to flag non-matching identifiers
 * @author Matthieu Larcher
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require identifiers to match a specified regular expression",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                type: "string"
            },
            {
                type: "object",
                properties: {
                    properties: {
                        type: "boolean"
                    }
                }
            }
        ]
    },
 
    create(context) {
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        const pattern = context.options[0] || "^.+$",
            regexp = new RegExp(pattern);
 
        const options = context.options[1] || {},
            properties = !!options.properties,
            onlyDeclarations = !!options.onlyDeclarations;
 
        /**
         * Checks if a string matches the provided pattern
         * @param {string} name The string to check.
         * @returns {boolean} if the string is a match
         * @private
         */
        function isInvalid(name) {
            return !regexp.test(name);
        }
 
        /**
         * Verifies if we should report an error or not based on the effective
         * parent node and the identifier name.
         * @param {ASTNode} effectiveParent The effective parent node of the node to be reported
         * @param {string} name The identifier name of the identifier node
         * @returns {boolean} whether an error should be reported or not
         */
        function shouldReport(effectiveParent, name) {
            return effectiveParent.type !== "CallExpression" &&
                effectiveParent.type !== "NewExpression" &&
                isInvalid(name);
        }
 
        /**
         * Reports an AST node as a rule violation.
         * @param {ASTNode} node The node to report.
         * @returns {void}
         * @private
         */
        function report(node) {
            context.report({ node, message: "Identifier '{{name}}' does not match the pattern '{{pattern}}'.", data: {
                name: node.name,
                pattern
            } });
        }
 
        return {
 
            Identifier(node) {
                const name = node.name,
                    parent = node.parent,
                    effectiveParent = (parent.type === "MemberExpression") ? parent.parent : parent;
 
                if (parent.type === "MemberExpression") {
 
                    if (!properties) {
                        return;
                    }
 
                    // Always check object names
                    if (parent.object.type === "Identifier" &&
                        parent.object.name === name) {
                        if (isInvalid(name)) {
                            report(node);
                        }
 
                    // Report AssignmentExpressions only if they are the left side of the assignment
                    } else if (effectiveParent.type === "AssignmentExpression" &&
                        (effectiveParent.right.type !== "MemberExpression" ||
                        effectiveParent.left.type === "MemberExpression" &&
                        effectiveParent.left.property.name === name)) {
                        if (isInvalid(name)) {
                            report(node);
                        }
                    }
 
                } else if (parent.type === "Property") {
 
                    if (!properties || parent.key.name !== name) {
                        return;
                    }
 
                    if (shouldReport(effectiveParent, name)) {
                        report(node);
                    }
 
                } else {
                    const isDeclaration = effectiveParent.type === "FunctionDeclaration" || effectiveParent.type === "VariableDeclarator";
 
                    if (onlyDeclarations && !isDeclaration) {
                        return;
                    }
 
                    if (shouldReport(effectiveParent, name)) {
                        report(node);
                    }
                }
            }
 
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/indent.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/indent.js

Statements: 8.18% (27 / 330)      Branches: 0.29% (1 / 350)      Functions: 0% (0 / 38)      Lines: 8.31% (27 / 325)      Ignored: 1 branch     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124                            1           1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   1                                                                 1                                                           1                                         1                             1                                                                                               1                   1                                             1                                                                 1                                           1                                       1                     1                       1                             1                                                                                     1                                                                                                                                                             1                           1                         1                                                                                                                                                                                                       1                   1                                                                                                                   1                                   1                                                             1                       1                                                     1                                                                                                                                                                                                                                                                                                                                      
/**
 * @fileoverview This option sets a specific tab width for your code
 *
 * This rule has been ported and modified from nodeca.
 * @author Vitaly Puzrin
 * @author Gyandeep Singh
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent indentation",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                oneOf: [
                    {
                        enum: ["tab"]
                    },
                    {
                        type: "integer",
                        minimum: 0
                    }
                ]
            },
            {
                type: "object",
                properties: {
                    SwitchCase: {
                        type: "integer",
                        minimum: 0
                    },
                    VariableDeclarator: {
                        oneOf: [
                            {
                                type: "integer",
                                minimum: 0
                            },
                            {
                                type: "object",
                                properties: {
                                    var: {
                                        type: "integer",
                                        minimum: 0
                                    },
                                    let: {
                                        type: "integer",
                                        minimum: 0
                                    },
                                    const: {
                                        type: "integer",
                                        minimum: 0
                                    }
                                }
                            }
                        ]
                    },
                    outerIIFEBody: {
                        type: "integer",
                        minimum: 0
                    },
                    MemberExpression: {
                        type: "integer",
                        minimum: 0
                    },
                    FunctionDeclaration: {
                        type: "object",
                        properties: {
                            parameters: {
                                oneOf: [
                                    {
                                        type: "integer",
                                        minimum: 0
                                    },
                                    {
                                        enum: ["first"]
                                    }
                                ]
                            },
                            body: {
                                type: "integer",
                                minimum: 0
                            }
                        }
                    },
                    FunctionExpression: {
                        type: "object",
                        properties: {
                            parameters: {
                                oneOf: [
                                    {
                                        type: "integer",
                                        minimum: 0
                                    },
                                    {
                                        enum: ["first"]
                                    }
                                ]
                            },
                            body: {
                                type: "integer",
                                minimum: 0
                            }
                        }
                    },
                    CallExpression: {
                        type: "object",
                        properties: {
                            parameters: {
                                oneOf: [
                                    {
                                        type: "integer",
                                        minimum: 0
                                    },
                                    {
                                        enum: ["first"]
                                    }
                                ]
                            }
                        }
                    },
                    ArrayExpression: {
                        oneOf: [
                            {
                                type: "integer",
                                minimum: 0
                            },
                            {
                                enum: ["first"]
                            }
                        ]
                    },
                    ObjectExpression: {
                        oneOf: [
                            {
                                type: "integer",
                                minimum: 0
                            },
                            {
                                enum: ["first"]
                            }
                        ]
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const DEFAULT_VARIABLE_INDENT = 1;
        const DEFAULT_PARAMETER_INDENT = null; // For backwards compatibility, don't check parameter indentation unless specified in the config
        const DEFAULT_FUNCTION_BODY_INDENT = 1;
 
        let indentType = "space";
        let indentSize = 4;
        const options = {
            SwitchCase: 0,
            VariableDeclarator: {
                var: DEFAULT_VARIABLE_INDENT,
                let: DEFAULT_VARIABLE_INDENT,
                const: DEFAULT_VARIABLE_INDENT
            },
            outerIIFEBody: null,
            FunctionDeclaration: {
                parameters: DEFAULT_PARAMETER_INDENT,
                body: DEFAULT_FUNCTION_BODY_INDENT
            },
            FunctionExpression: {
                parameters: DEFAULT_PARAMETER_INDENT,
                body: DEFAULT_FUNCTION_BODY_INDENT
            },
            CallExpression: {
                arguments: DEFAULT_PARAMETER_INDENT
            },
            ArrayExpression: 1,
            ObjectExpression: 1
        };
 
        const sourceCode = context.getSourceCode();
 
        if (context.options.length) {
            if (context.options[0] === "tab") {
                indentSize = 1;
                indentType = "tab";
            } else /* istanbul ignore else : this will be caught by options validation */ if (typeof context.options[0] === "number") {
                indentSize = context.options[0];
                indentType = "space";
            }
 
            if (context.options[1]) {
                const opts = context.options[1];
 
                options.SwitchCase = opts.SwitchCase || 0;
                const variableDeclaratorRules = opts.VariableDeclarator;
 
                if (typeof variableDeclaratorRules === "number") {
                    options.VariableDeclarator = {
                        var: variableDeclaratorRules,
                        let: variableDeclaratorRules,
                        const: variableDeclaratorRules
                    };
                } else if (typeof variableDeclaratorRules === "object") {
                    Object.assign(options.VariableDeclarator, variableDeclaratorRules);
                }
 
                if (typeof opts.outerIIFEBody === "number") {
                    options.outerIIFEBody = opts.outerIIFEBody;
                }
 
                if (typeof opts.MemberExpression === "number") {
                    options.MemberExpression = opts.MemberExpression;
                }
 
                if (typeof opts.FunctionDeclaration === "object") {
                    Object.assign(options.FunctionDeclaration, opts.FunctionDeclaration);
                }
 
                if (typeof opts.FunctionExpression === "object") {
                    Object.assign(options.FunctionExpression, opts.FunctionExpression);
                }
 
                if (typeof opts.CallExpression === "object") {
                    Object.assign(options.CallExpression, opts.CallExpression);
                }
 
                if (typeof opts.ArrayExpression === "number" || typeof opts.ArrayExpression === "string") {
                    options.ArrayExpression = opts.ArrayExpression;
                }
 
                if (typeof opts.ObjectExpression === "number" || typeof opts.ObjectExpression === "string") {
                    options.ObjectExpression = opts.ObjectExpression;
                }
            }
        }
 
        const caseIndentStore = {};
 
        /**
         * Creates an error message for a line, given the expected/actual indentation.
         * @param {int} expectedAmount The expected amount of indentation characters for this line
         * @param {int} actualSpaces The actual number of indentation spaces that were found on this line
         * @param {int} actualTabs The actual number of indentation tabs that were found on this line
         * @returns {string} An error message for this line
         */
        function createErrorMessage(expectedAmount, actualSpaces, actualTabs) {
            const expectedStatement = `${expectedAmount} ${indentType}${expectedAmount === 1 ? "" : "s"}`; // e.g. "2 tabs"
            const foundSpacesWord = `space${actualSpaces === 1 ? "" : "s"}`; // e.g. "space"
            const foundTabsWord = `tab${actualTabs === 1 ? "" : "s"}`; // e.g. "tabs"
            let foundStatement;
 
            if (actualSpaces > 0 && actualTabs > 0) {
                foundStatement = `${actualSpaces} ${foundSpacesWord} and ${actualTabs} ${foundTabsWord}`; // e.g. "1 space and 2 tabs"
            } else if (actualSpaces > 0) {
 
                // Abbreviate the message if the expected indentation is also spaces.
                // e.g. 'Expected 4 spaces but found 2' rather than 'Expected 4 spaces but found 2 spaces'
                foundStatement = indentType === "space" ? actualSpaces : `${actualSpaces} ${foundSpacesWord}`;
            } else if (actualTabs > 0) {
                foundStatement = indentType === "tab" ? actualTabs : `${actualTabs} ${foundTabsWord}`;
            } else {
                foundStatement = "0";
            }
 
            return `Expected indentation of ${expectedStatement} but found ${foundStatement}.`;
        }
 
        /**
         * Reports a given indent violation
         * @param {ASTNode} node Node violating the indent rule
         * @param {int} needed Expected indentation character count
         * @param {int} gottenSpaces Indentation space count in the actual node/code
         * @param {int} gottenTabs Indentation tab count in the actual node/code
         * @param {Object=} loc Error line and column location
         * @param {boolean} isLastNodeCheck Is the error for last node check
         * @param {int} lastNodeCheckEndOffset Number of charecters to skip from the end
         * @returns {void}
         */
        function report(node, needed, gottenSpaces, gottenTabs, loc, isLastNodeCheck) {
            if (gottenSpaces && gottenTabs) {
 
                // To avoid conflicts with `no-mixed-spaces-and-tabs`, don't report lines that have both spaces and tabs.
                return;
            }
 
            const desiredIndent = (indentType === "space" ? " " : "\t").repeat(needed);
 
            const textRange = isLastNodeCheck
                ? [node.range[1] - node.loc.end.column, node.range[1] - node.loc.end.column + gottenSpaces + gottenTabs]
                : [node.range[0] - node.loc.start.column, node.range[0] - node.loc.start.column + gottenSpaces + gottenTabs];
 
            context.report({
                node,
                loc,
                message: createErrorMessage(needed, gottenSpaces, gottenTabs),
                fix: fixer => fixer.replaceTextRange(textRange, desiredIndent)
            });
        }
 
        /**
         * Get the actual indent of node
         * @param {ASTNode|Token} node Node to examine
         * @param {boolean} [byLastLine=false] get indent of node's last line
         * @param {boolean} [excludeCommas=false] skip comma on start of line
         * @returns {Object} The node's indent. Contains keys `space` and `tab`, representing the indent of each character. Also
         contains keys `goodChar` and `badChar`, where `goodChar` is the amount of the user's desired indentation character, and
         `badChar` is the amount of the other indentation character.
         */
        function getNodeIndent(node, byLastLine) {
            const token = byLastLine ? sourceCode.getLastToken(node) : sourceCode.getFirstToken(node);
            const srcCharsBeforeNode = sourceCode.getText(token, token.loc.start.column).split("");
            const indentChars = srcCharsBeforeNode.slice(0, srcCharsBeforeNode.findIndex(char => char !== " " && char !== "\t"));
            const spaces = indentChars.filter(char => char === " ").length;
            const tabs = indentChars.filter(char => char === "\t").length;
 
            return {
                space: spaces,
                tab: tabs,
                goodChar: indentType === "space" ? spaces : tabs,
                badChar: indentType === "space" ? tabs : spaces
            };
        }
 
        /**
         * Checks node is the first in its own start line. By default it looks by start line.
         * @param {ASTNode} node The node to check
         * @param {boolean} [byEndLocation=false] Lookup based on start position or end
         * @returns {boolean} true if its the first in the its start line
         */
        function isNodeFirstInLine(node, byEndLocation) {
            const firstToken = byEndLocation === true ? sourceCode.getLastToken(node, 1) : sourceCode.getTokenBefore(node),
                startLine = byEndLocation === true ? node.loc.end.line : node.loc.start.line,
                endLine = firstToken ? firstToken.loc.end.line : -1;
 
            return startLine !== endLine;
        }
 
        /**
         * Check indent for node
         * @param {ASTNode} node Node to check
         * @param {int} neededIndent needed indent
         * @param {boolean} [excludeCommas=false] skip comma on start of line
         * @returns {void}
         */
        function checkNodeIndent(node, neededIndent) {
            const actualIndent = getNodeIndent(node, false);
 
            if (
                node.type !== "ArrayExpression" &&
                node.type !== "ObjectExpression" &&
                (actualIndent.goodChar !== neededIndent || actualIndent.badChar !== 0) &&
                isNodeFirstInLine(node)
            ) {
                report(node, neededIndent, actualIndent.space, actualIndent.tab);
            }
 
            if (node.type === "IfStatement" && node.alternate) {
                const elseToken = sourceCode.getTokenBefore(node.alternate);
 
                checkNodeIndent(elseToken, neededIndent);
 
                if (!isNodeFirstInLine(node.alternate)) {
                    checkNodeIndent(node.alternate, neededIndent);
                }
            }
 
            if (node.type === "TryStatement" && node.handler) {
                const catchToken = sourceCode.getFirstToken(node.handler);
 
                checkNodeIndent(catchToken, neededIndent);
            }
 
            if (node.type === "TryStatement" && node.finalizer) {
                const finallyToken = sourceCode.getTokenBefore(node.finalizer);
 
                checkNodeIndent(finallyToken, neededIndent);
            }
 
            if (node.type === "DoWhileStatement") {
                const whileToken = sourceCode.getTokenAfter(node.body);
 
                checkNodeIndent(whileToken, neededIndent);
            }
        }
 
        /**
         * Check indent for nodes list
         * @param {ASTNode[]} nodes list of node objects
         * @param {int} indent needed indent
         * @param {boolean} [excludeCommas=false] skip comma on start of line
         * @returns {void}
         */
        function checkNodesIndent(nodes, indent) {
            nodes.forEach(node => checkNodeIndent(node, indent));
        }
 
        /**
         * Check last node line indent this detects, that block closed correctly
         * @param {ASTNode} node Node to examine
         * @param {int} lastLineIndent needed indent
         * @returns {void}
         */
        function checkLastNodeLineIndent(node, lastLineIndent) {
            const lastToken = sourceCode.getLastToken(node);
            const endIndent = getNodeIndent(lastToken, true);
 
            if ((endIndent.goodChar !== lastLineIndent || endIndent.badChar !== 0) && isNodeFirstInLine(node, true)) {
                report(
                    node,
                    lastLineIndent,
                    endIndent.space,
                    endIndent.tab,
                    { line: lastToken.loc.start.line, column: lastToken.loc.start.column },
                    true
                );
            }
        }
 
        /**
         * Check last node line indent this detects, that block closed correctly
         * This function for more complicated return statement case, where closing parenthesis may be followed by ';'
         * @param {ASTNode} node Node to examine
         * @param {int} firstLineIndent first line needed indent
         * @returns {void}
         */
        function checkLastReturnStatementLineIndent(node, firstLineIndent) {
 
            // in case if return statement ends with ');' we have traverse back to ')'
            // otherwise we'll measure indent for ';' and replace ')'
            const lastToken = sourceCode.getLastToken(node, astUtils.isClosingParenToken);
            const textBeforeClosingParenthesis = sourceCode.getText(lastToken, lastToken.loc.start.column).slice(0, -1);
 
            if (textBeforeClosingParenthesis.trim()) {
 
                // There are tokens before the closing paren, don't report this case
                return;
            }
 
            const endIndent = getNodeIndent(lastToken, true);
 
            if (endIndent.goodChar !== firstLineIndent) {
                report(
                    node,
                    firstLineIndent,
                    endIndent.space,
                    endIndent.tab,
                    { line: lastToken.loc.start.line, column: lastToken.loc.start.column },
                    true
                );
            }
        }
 
        /**
         * Check first node line indent is correct
         * @param {ASTNode} node Node to examine
         * @param {int} firstLineIndent needed indent
         * @returns {void}
         */
        function checkFirstNodeLineIndent(node, firstLineIndent) {
            const startIndent = getNodeIndent(node, false);
 
            if ((startIndent.goodChar !== firstLineIndent || startIndent.badChar !== 0) && isNodeFirstInLine(node)) {
                report(
                    node,
                    firstLineIndent,
                    startIndent.space,
                    startIndent.tab,
                    { line: node.loc.start.line, column: node.loc.start.column }
                );
            }
        }
 
        /**
         * Returns a parent node of given node based on a specified type
         * if not present then return null
         * @param {ASTNode} node node to examine
         * @param {string} type type that is being looked for
         * @param {string} stopAtList end points for the evaluating code
         * @returns {ASTNode|void} if found then node otherwise null
         */
        function getParentNodeByType(node, type, stopAtList) {
            let parent = node.parent;
 
            if (!stopAtList) {
                stopAtList = ["Program"];
            }
 
            while (parent.type !== type && stopAtList.indexOf(parent.type) === -1 && parent.type !== "Program") {
                parent = parent.parent;
            }
 
            return parent.type === type ? parent : null;
        }
 
        /**
         * Returns the VariableDeclarator based on the current node
         * if not present then return null
         * @param {ASTNode} node node to examine
         * @returns {ASTNode|void} if found then node otherwise null
         */
        function getVariableDeclaratorNode(node) {
            return getParentNodeByType(node, "VariableDeclarator");
        }
 
        /**
         * Check to see if the node is part of the multi-line variable declaration.
         * Also if its on the same line as the varNode
         * @param {ASTNode} node node to check
         * @param {ASTNode} varNode variable declaration node to check against
         * @returns {boolean} True if all the above condition satisfy
         */
        function isNodeInVarOnTop(node, varNode) {
            return varNode &&
                varNode.parent.loc.start.line === node.loc.start.line &&
                varNode.parent.declarations.length > 1;
        }
 
        /**
         * Check to see if the argument before the callee node is multi-line and
         * there should only be 1 argument before the callee node
         * @param {ASTNode} node node to check
         * @returns {boolean} True if arguments are multi-line
         */
        function isArgBeforeCalleeNodeMultiline(node) {
            const parent = node.parent;
 
            if (parent.arguments.length >= 2 && parent.arguments[1] === node) {
                return parent.arguments[0].loc.end.line > parent.arguments[0].loc.start.line;
            }
 
            return false;
        }
 
        /**
         * Check to see if the node is a file level IIFE
         * @param {ASTNode} node The function node to check.
         * @returns {boolean} True if the node is the outer IIFE
         */
        function isOuterIIFE(node) {
            const parent = node.parent;
            let stmt = parent.parent;
 
            /*
             * Verify that the node is an IIEF
             */
            if (
                parent.type !== "CallExpression" ||
                parent.callee !== node) {
 
                return false;
            }
 
            /*
             * Navigate legal ancestors to determine whether this IIEF is outer
             */
            while (
                stmt.type === "UnaryExpression" && (
                    stmt.operator === "!" ||
                    stmt.operator === "~" ||
                    stmt.operator === "+" ||
                    stmt.operator === "-") ||
                stmt.type === "AssignmentExpression" ||
                stmt.type === "LogicalExpression" ||
                stmt.type === "SequenceExpression" ||
                stmt.type === "VariableDeclarator") {
 
                stmt = stmt.parent;
            }
 
            return ((
                    stmt.type === "ExpressionStatement" ||
                    stmt.type === "VariableDeclaration") &&
                stmt.parent && stmt.parent.type === "Program"
            );
        }
 
        /**
         * Check indent for function block content
         * @param {ASTNode} node A BlockStatement node that is inside of a function.
         * @returns {void}
         */
        function checkIndentInFunctionBlock(node) {
 
            /*
             * Search first caller in chain.
             * Ex.:
             *
             * Models <- Identifier
             *   .User
             *   .find()
             *   .exec(function() {
             *   // function body
             * });
             *
             * Looks for 'Models'
             */
            const calleeNode = node.parent; // FunctionExpression
            let indent;
 
            if (calleeNode.parent &&
                (calleeNode.parent.type === "Property" ||
                calleeNode.parent.type === "ArrayExpression")) {
 
                // If function is part of array or object, comma can be put at left
                indent = getNodeIndent(calleeNode, false, false).goodChar;
            } else {
 
                // If function is standalone, simple calculate indent
                indent = getNodeIndent(calleeNode).goodChar;
            }
 
            if (calleeNode.parent.type === "CallExpression") {
                const calleeParent = calleeNode.parent;
 
                if (calleeNode.type !== "FunctionExpression" && calleeNode.type !== "ArrowFunctionExpression") {
                    if (calleeParent && calleeParent.loc.start.line < node.loc.start.line) {
                        indent = getNodeIndent(calleeParent).goodChar;
                    }
                } else {
                    if (isArgBeforeCalleeNodeMultiline(calleeNode) &&
                        calleeParent.callee.loc.start.line === calleeParent.callee.loc.end.line &&
                        !isNodeFirstInLine(calleeNode)) {
                        indent = getNodeIndent(calleeParent).goodChar;
                    }
                }
            }
 
            // function body indent should be indent + indent size, unless this
            // is a FunctionDeclaration, FunctionExpression, or outer IIFE and the corresponding options are enabled.
            let functionOffset = indentSize;
 
            if (options.outerIIFEBody !== null && isOuterIIFE(calleeNode)) {
                functionOffset = options.outerIIFEBody * indentSize;
            } else if (calleeNode.type === "FunctionExpression") {
                functionOffset = options.FunctionExpression.body * indentSize;
            } else if (calleeNode.type === "FunctionDeclaration") {
                functionOffset = options.FunctionDeclaration.body * indentSize;
            }
            indent += functionOffset;
 
            // check if the node is inside a variable
            const parentVarNode = getVariableDeclaratorNode(node);
 
            if (parentVarNode && isNodeInVarOnTop(node, parentVarNode)) {
                indent += indentSize * options.VariableDeclarator[parentVarNode.parent.kind];
            }
 
            if (node.body.length > 0) {
                checkNodesIndent(node.body, indent);
            }
 
            checkLastNodeLineIndent(node, indent - functionOffset);
        }
 
 
        /**
         * Checks if the given node starts and ends on the same line
         * @param {ASTNode} node The node to check
         * @returns {boolean} Whether or not the block starts and ends on the same line.
         */
        function isSingleLineNode(node) {
            const lastToken = sourceCode.getLastToken(node),
                startLine = node.loc.start.line,
                endLine = lastToken.loc.end.line;
 
            return startLine === endLine;
        }
 
        /**
         * Check to see if the first element inside an array is an object and on the same line as the node
         * If the node is not an array then it will return false.
         * @param {ASTNode} node node to check
         * @returns {boolean} success/failure
         */
        function isFirstArrayElementOnSameLine(node) {
            if (node.type === "ArrayExpression" && node.elements[0]) {
                return node.elements[0].loc.start.line === node.loc.start.line && node.elements[0].type === "ObjectExpression";
            }
            return false;
 
        }
 
        /**
         * Check indent for array block content or object block content
         * @param {ASTNode} node node to examine
         * @returns {void}
         */
        function checkIndentInArrayOrObjectBlock(node) {
 
            // Skip inline
            if (isSingleLineNode(node)) {
                return;
            }
 
            let elements = (node.type === "ArrayExpression") ? node.elements : node.properties;
 
            // filter out empty elements example would be [ , 2] so remove first element as espree considers it as null
            elements = elements.filter(elem => elem !== null);
 
            let nodeIndent;
            let elementsIndent;
            const parentVarNode = getVariableDeclaratorNode(node);
 
            // TODO - come up with a better strategy in future
            if (isNodeFirstInLine(node)) {
                const parent = node.parent;
 
                nodeIndent = getNodeIndent(parent).goodChar;
                if (!parentVarNode || parentVarNode.loc.start.line !== node.loc.start.line) {
                    if (parent.type !== "VariableDeclarator" || parentVarNode === parentVarNode.parent.declarations[0]) {
                        if (parent.type === "VariableDeclarator" && parentVarNode.loc.start.line === parent.loc.start.line) {
                            nodeIndent = nodeIndent + (indentSize * options.VariableDeclarator[parentVarNode.parent.kind]);
                        } else if (parent.type === "ObjectExpression" || parent.type === "ArrayExpression") {
                            const parentElements = node.parent.type === "ObjectExpression" ? node.parent.properties : node.parent.elements;
 
                            if (parentElements[0] && parentElements[0].loc.start.line === parent.loc.start.line && parentElements[0].loc.end.line !== parent.loc.start.line) {
 
                                /*
                                 * If the first element of the array spans multiple lines, don't increase the expected indentation of the rest.
                                 * e.g. [{
                                 *        foo: 1
                                 *      },
                                 *      {
                                 *        bar: 1
                                 *      }]
                                 * the second object is not indented.
                                 */
                            } else if (typeof options[parent.type] === "number") {
                                nodeIndent += options[parent.type] * indentSize;
                            } else {
                                nodeIndent = parentElements[0].loc.start.column;
                            }
                        } else if (parent.type === "CallExpression" || parent.type === "NewExpression") {
                            if (typeof options.CallExpression.arguments === "number") {
                                nodeIndent += options.CallExpression.arguments * indentSize;
                            } else if (options.CallExpression.arguments === "first") {
                                if (parent.arguments.indexOf(node) !== -1) {
                                    nodeIndent = parent.arguments[0].loc.start.column;
                                }
                            } else {
                                nodeIndent += indentSize;
                            }
                        } else if (parent.type === "LogicalExpression" || parent.type === "ArrowFunctionExpression") {
                            nodeIndent += indentSize;
                        }
                    }
                } else if (!parentVarNode && !isFirstArrayElementOnSameLine(parent) && parent.type !== "MemberExpression" && parent.type !== "ExpressionStatement" && parent.type !== "AssignmentExpression" && parent.type !== "Property") {
                    nodeIndent = nodeIndent + indentSize;
                }
 
                checkFirstNodeLineIndent(node, nodeIndent);
            } else {
                nodeIndent = getNodeIndent(node).goodChar;
            }
 
            if (options[node.type] === "first") {
                elementsIndent = elements.length ? elements[0].loc.start.column : 0; // If there are no elements, elementsIndent doesn't matter.
            } else {
                elementsIndent = nodeIndent + indentSize * options[node.type];
            }
 
            /*
             * Check if the node is a multiple variable declaration; if so, then
             * make sure indentation takes that into account.
             */
            if (isNodeInVarOnTop(node, parentVarNode)) {
                elementsIndent += indentSize * options.VariableDeclarator[parentVarNode.parent.kind];
            }
 
            checkNodesIndent(elements, elementsIndent);
 
            if (elements.length > 0) {
 
                // Skip last block line check if last item in same line
                if (elements[elements.length - 1].loc.end.line === node.loc.end.line) {
                    return;
                }
            }
 
            checkLastNodeLineIndent(node, nodeIndent + (isNodeInVarOnTop(node, parentVarNode) ? options.VariableDeclarator[parentVarNode.parent.kind] * indentSize : 0));
        }
 
        /**
         * Check if the node or node body is a BlockStatement or not
         * @param {ASTNode} node node to test
         * @returns {boolean} True if it or its body is a block statement
         */
        function isNodeBodyBlock(node) {
            return node.type === "BlockStatement" || node.type === "ClassBody" || (node.body && node.body.type === "BlockStatement") ||
                (node.consequent && node.consequent.type === "BlockStatement");
        }
 
        /**
         * Check indentation for blocks
         * @param {ASTNode} node node to check
         * @returns {void}
         */
        function blockIndentationCheck(node) {
 
            // Skip inline blocks
            if (isSingleLineNode(node)) {
                return;
            }
 
            if (node.parent && (
                    node.parent.type === "FunctionExpression" ||
                    node.parent.type === "FunctionDeclaration" ||
                    node.parent.type === "ArrowFunctionExpression"
            )) {
                checkIndentInFunctionBlock(node);
                return;
            }
 
            let indent;
            let nodesToCheck = [];
 
            /*
             * For this statements we should check indent from statement beginning,
             * not from the beginning of the block.
             */
            const statementsWithProperties = [
                "IfStatement", "WhileStatement", "ForStatement", "ForInStatement", "ForOfStatement", "DoWhileStatement", "ClassDeclaration", "TryStatement"
            ];
 
            if (node.parent && statementsWithProperties.indexOf(node.parent.type) !== -1 && isNodeBodyBlock(node)) {
                indent = getNodeIndent(node.parent).goodChar;
            } else if (node.parent && node.parent.type === "CatchClause") {
                indent = getNodeIndent(node.parent.parent).goodChar;
            } else {
                indent = getNodeIndent(node).goodChar;
            }
 
            if (node.type === "IfStatement" && node.consequent.type !== "BlockStatement") {
                nodesToCheck = [node.consequent];
            } else if (Array.isArray(node.body)) {
                nodesToCheck = node.body;
            } else {
                nodesToCheck = [node.body];
            }
 
            if (nodesToCheck.length > 0) {
                checkNodesIndent(nodesToCheck, indent + indentSize);
            }
 
            if (node.type === "BlockStatement") {
                checkLastNodeLineIndent(node, indent);
            }
        }
 
        /**
         * Filter out the elements which are on the same line of each other or the node.
         * basically have only 1 elements from each line except the variable declaration line.
         * @param {ASTNode} node Variable declaration node
         * @returns {ASTNode[]} Filtered elements
         */
        function filterOutSameLineVars(node) {
            return node.declarations.reduce((finalCollection, elem) => {
                const lastElem = finalCollection[finalCollection.length - 1];
 
                if ((elem.loc.start.line !== node.loc.start.line && !lastElem) ||
                    (lastElem && lastElem.loc.start.line !== elem.loc.start.line)) {
                    finalCollection.push(elem);
                }
 
                return finalCollection;
            }, []);
        }
 
        /**
         * Check indentation for variable declarations
         * @param {ASTNode} node node to examine
         * @returns {void}
         */
        function checkIndentInVariableDeclarations(node) {
            const elements = filterOutSameLineVars(node);
            const nodeIndent = getNodeIndent(node).goodChar;
            const lastElement = elements[elements.length - 1];
 
            const elementsIndent = nodeIndent + indentSize * options.VariableDeclarator[node.kind];
 
            checkNodesIndent(elements, elementsIndent);
 
            // Only check the last line if there is any token after the last item
            if (sourceCode.getLastToken(node).loc.end.line <= lastElement.loc.end.line) {
                return;
            }
 
            const tokenBeforeLastElement = sourceCode.getTokenBefore(lastElement);
 
            if (tokenBeforeLastElement.value === ",") {
 
                // Special case for comma-first syntax where the semicolon is indented
                checkLastNodeLineIndent(node, getNodeIndent(tokenBeforeLastElement).goodChar);
            } else {
                checkLastNodeLineIndent(node, elementsIndent - indentSize);
            }
        }
 
        /**
         * Check and decide whether to check for indentation for blockless nodes
         * Scenarios are for or while statements without braces around them
         * @param {ASTNode} node node to examine
         * @returns {void}
         */
        function blockLessNodes(node) {
            if (node.body.type !== "BlockStatement") {
                blockIndentationCheck(node);
            }
        }
 
        /**
         * Returns the expected indentation for the case statement
         * @param {ASTNode} node node to examine
         * @param {int} [switchIndent] indent for switch statement
         * @returns {int} indent size
         */
        function expectedCaseIndent(node, switchIndent) {
            const switchNode = (node.type === "SwitchStatement") ? node : node.parent;
            let caseIndent;
 
            if (caseIndentStore[switchNode.loc.start.line]) {
                return caseIndentStore[switchNode.loc.start.line];
            }
            if (typeof switchIndent === "undefined") {
                switchIndent = getNodeIndent(switchNode).goodChar;
            }
 
            if (switchNode.cases.length > 0 && options.SwitchCase === 0) {
                caseIndent = switchIndent;
            } else {
                caseIndent = switchIndent + (indentSize * options.SwitchCase);
            }
 
            caseIndentStore[switchNode.loc.start.line] = caseIndent;
            return caseIndent;
 
        }
 
        /**
         * Checks wether a return statement is wrapped in ()
         * @param {ASTNode} node node to examine
         * @returns {boolean} the result
         */
        function isWrappedInParenthesis(node) {
            const regex = /^return\s*?\(\s*?\);*?/;
 
            const statementWithoutArgument = sourceCode.getText(node).replace(
                sourceCode.getText(node.argument), "");
 
            return regex.test(statementWithoutArgument);
        }
 
        return {
            Program(node) {
                if (node.body.length > 0) {
 
                    // Root nodes should have no indent
                    checkNodesIndent(node.body, getNodeIndent(node).goodChar);
                }
            },
 
            ClassBody: blockIndentationCheck,
 
            BlockStatement: blockIndentationCheck,
 
            WhileStatement: blockLessNodes,
 
            ForStatement: blockLessNodes,
 
            ForInStatement: blockLessNodes,
 
            ForOfStatement: blockLessNodes,
 
            DoWhileStatement: blockLessNodes,
 
            IfStatement(node) {
                if (node.consequent.type !== "BlockStatement" && node.consequent.loc.start.line > node.loc.start.line) {
                    blockIndentationCheck(node);
                }
            },
 
            VariableDeclaration(node) {
                if (node.declarations[node.declarations.length - 1].loc.start.line > node.declarations[0].loc.start.line) {
                    checkIndentInVariableDeclarations(node);
                }
            },
 
            ObjectExpression(node) {
                checkIndentInArrayOrObjectBlock(node);
            },
 
            ArrayExpression(node) {
                checkIndentInArrayOrObjectBlock(node);
            },
 
            MemberExpression(node) {
 
                if (typeof options.MemberExpression === "undefined") {
                    return;
                }
 
                if (isSingleLineNode(node)) {
                    return;
                }
 
                // The typical layout of variable declarations and assignments
                // alter the expectation of correct indentation. Skip them.
                // TODO: Add appropriate configuration options for variable
                // declarations and assignments.
                if (getParentNodeByType(node, "VariableDeclarator", ["FunctionExpression", "ArrowFunctionExpression"])) {
                    return;
                }
 
                if (getParentNodeByType(node, "AssignmentExpression", ["FunctionExpression"])) {
                    return;
                }
 
                const propertyIndent = getNodeIndent(node).goodChar + indentSize * options.MemberExpression;
 
                const checkNodes = [node.property];
 
                const dot = context.getTokenBefore(node.property);
 
                if (dot.type === "Punctuator" && dot.value === ".") {
                    checkNodes.push(dot);
                }
 
                checkNodesIndent(checkNodes, propertyIndent);
            },
 
            SwitchStatement(node) {
 
                // Switch is not a 'BlockStatement'
                const switchIndent = getNodeIndent(node).goodChar;
                const caseIndent = expectedCaseIndent(node, switchIndent);
 
                checkNodesIndent(node.cases, caseIndent);
 
 
                checkLastNodeLineIndent(node, switchIndent);
            },
 
            SwitchCase(node) {
 
                // Skip inline cases
                if (isSingleLineNode(node)) {
                    return;
                }
                const caseIndent = expectedCaseIndent(node);
 
                checkNodesIndent(node.consequent, caseIndent + indentSize);
            },
 
            FunctionDeclaration(node) {
                if (isSingleLineNode(node)) {
                    return;
                }
                if (options.FunctionDeclaration.parameters === "first" && node.params.length) {
                    checkNodesIndent(node.params.slice(1), node.params[0].loc.start.column);
                } else if (options.FunctionDeclaration.parameters !== null) {
                    checkNodesIndent(node.params, getNodeIndent(node).goodChar + indentSize * options.FunctionDeclaration.parameters);
                }
            },
 
            FunctionExpression(node) {
                if (isSingleLineNode(node)) {
                    return;
                }
                if (options.FunctionExpression.parameters === "first" && node.params.length) {
                    checkNodesIndent(node.params.slice(1), node.params[0].loc.start.column);
                } else if (options.FunctionExpression.parameters !== null) {
                    checkNodesIndent(node.params, getNodeIndent(node).goodChar + indentSize * options.FunctionExpression.parameters);
                }
            },
 
            ReturnStatement(node) {
                if (isSingleLineNode(node)) {
                    return;
                }
 
                const firstLineIndent = getNodeIndent(node).goodChar;
 
                // in case if return statement is wrapped in parenthesis
                if (isWrappedInParenthesis(node)) {
                    checkLastReturnStatementLineIndent(node, firstLineIndent);
                } else {
                    checkNodeIndent(node, firstLineIndent);
                }
            },
 
            CallExpression(node) {
                if (isSingleLineNode(node)) {
                    return;
                }
                if (options.CallExpression.arguments === "first" && node.arguments.length) {
                    checkNodesIndent(node.arguments.slice(1), node.arguments[0].loc.start.column);
                } else if (options.CallExpression.arguments !== null) {
                    checkNodesIndent(node.arguments, getNodeIndent(node).goodChar + indentSize * options.CallExpression.arguments);
                }
            }
 
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/init-declarations.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/init-declarations.js

Statements: 12.5% (3 / 24)      Branches: 0% (0 / 25)      Functions: 0% (0 / 4)      Lines: 12.5% (3 / 24)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139                                1                     1                                 1                                                                                                                                                                                            
/**
 * @fileoverview A rule to control the style of variable initializations.
 * @author Colin Ihrig
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks whether or not a given node is a for loop.
 * @param {ASTNode} block - A node to check.
 * @returns {boolean} `true` when the node is a for loop.
 */
function isForLoop(block) {
    return block.type === "ForInStatement" ||
    block.type === "ForOfStatement" ||
    block.type === "ForStatement";
}
 
/**
 * Checks whether or not a given declarator node has its initializer.
 * @param {ASTNode} node - A declarator node to check.
 * @returns {boolean} `true` when the node has its initializer.
 */
function isInitialized(node) {
    const declaration = node.parent;
    const block = declaration.parent;
 
    if (isForLoop(block)) {
        if (block.type === "ForStatement") {
            return block.init === declaration;
        }
        return block.left === declaration;
    }
    return Boolean(node.init);
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require or disallow initialization in variable declarations",
            category: "Variables",
            recommended: false
        },
 
        schema: {
            anyOf: [
                {
                    type: "array",
                    items: [
                        {
                            enum: ["always"]
                        }
                    ],
                    minItems: 0,
                    maxItems: 1
                },
                {
                    type: "array",
                    items: [
                        {
                            enum: ["never"]
                        },
                        {
                            type: "object",
                            properties: {
                                ignoreForLoopInit: {
                                    type: "boolean"
                                }
                            },
                            additionalProperties: false
                        }
                    ],
                    minItems: 0,
                    maxItems: 2
                }
            ]
        }
    },
 
    create(context) {
 
        const MODE_ALWAYS = "always",
            MODE_NEVER = "never";
 
        const mode = context.options[0] || MODE_ALWAYS;
        const params = context.options[1] || {};
 
        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------
 
        return {
            "VariableDeclaration:exit"(node) {
 
                const kind = node.kind,
                    declarations = node.declarations;
 
                for (let i = 0; i < declarations.length; ++i) {
                    const declaration = declarations[i],
                        id = declaration.id,
                        initialized = isInitialized(declaration),
                        isIgnoredForLoop = params.ignoreForLoopInit && isForLoop(node.parent);
 
                    if (id.type !== "Identifier") {
                        continue;
                    }
 
                    if (mode === MODE_ALWAYS && !initialized) {
                        context.report({
                            node: declaration,
                            message: "Variable '{{idName}}' should be initialized on declaration.",
                            data: {
                                idName: id.name
                            }
                        });
                    } else if (mode === MODE_NEVER && kind !== "const" && initialized && !isIgnoredForLoop) {
                        context.report({
                            node: declaration,
                            message: "Variable '{{idName}}' should not be initialized on declaration.",
                            data: {
                                idName: id.name
                            }
                        });
                    }
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/jsx-quotes.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/jsx-quotes.js

Statements: 30.77% (4 / 13)      Branches: 0% (0 / 9)      Functions: 0% (0 / 6)      Lines: 30.77% (4 / 13)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91                      1           1                                         1                                                     1                                                  
/**
 * @fileoverview A rule to ensure consistent quotes used in jsx syntax.
 * @author Mathias Schreck <https://github.com/lo1tuma>
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Constants
//------------------------------------------------------------------------------
 
const QUOTE_SETTINGS = {
    "prefer-double": {
        quote: "\"",
        description: "singlequote",
        convert(str) {
            return str.replace(/'/g, "\"");
        }
    },
    "prefer-single": {
        quote: "'",
        description: "doublequote",
        convert(str) {
            return str.replace(/"/g, "'");
        }
    }
};
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce the consistent use of either double or single quotes in JSX attributes",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                enum: ["prefer-single", "prefer-double"]
            }
        ]
    },
 
    create(context) {
        const quoteOption = context.options[0] || "prefer-double",
            setting = QUOTE_SETTINGS[quoteOption];
 
        /**
         * Checks if the given string literal node uses the expected quotes
         * @param {ASTNode} node - A string literal node.
         * @returns {boolean} Whether or not the string literal used the expected quotes.
         * @public
         */
        function usesExpectedQuotes(node) {
            return node.value.indexOf(setting.quote) !== -1 || astUtils.isSurroundedBy(node.raw, setting.quote);
        }
 
        return {
            JSXAttribute(node) {
                const attributeValue = node.value;
 
                if (attributeValue && astUtils.isStringLiteral(attributeValue) && !usesExpectedQuotes(attributeValue)) {
                    context.report({
                        node: attributeValue,
                        message: "Unexpected usage of {{description}}.",
                        data: {
                            description: setting.description
                        },
                        fix(fixer) {
                            return fixer.replaceText(attributeValue, setting.convert(attributeValue.raw));
                        }
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/key-spacing.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/key-spacing.js

Statements: 15.67% (21 / 134)      Branches: 0% (0 / 99)      Functions: 0% (0 / 24)      Lines: 15.67% (21 / 134)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641                    1                       1                 1                   1                                                                   1                   1                                                                               1                                                                 1         1                                                                                                                                                                                                                                                                                                                                                                                                   1                           1                       1                 1                                       1                                                                                                                               1                       1                                     1                                                   1                                                                                     1                       1                           1                                                                            
/**
 * @fileoverview Rule to specify spacing of object literal keys and values
 * @author Brandon Mills
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks whether a string contains a line terminator as defined in
 * http://www.ecma-international.org/ecma-262/5.1/#sec-7.3
 * @param {string} str String to test.
 * @returns {boolean} True if str contains a line terminator.
 */
function containsLineTerminator(str) {
    return astUtils.LINEBREAK_MATCHER.test(str);
}
 
/**
 * Gets the last element of an array.
 * @param {Array} arr An array.
 * @returns {any} Last element of arr.
 */
function last(arr) {
    return arr[arr.length - 1];
}
 
/**
 * Checks whether a property is a member of the property group it follows.
 * @param {ASTNode} lastMember The last Property known to be in the group.
 * @param {ASTNode} candidate The next Property that might be in the group.
 * @returns {boolean} True if the candidate property is part of the group.
 */
function continuesPropertyGroup(lastMember, candidate) {
    const groupEndLine = lastMember.loc.start.line,
        candidateStartLine = candidate.loc.start.line;
 
    if (candidateStartLine - groupEndLine <= 1) {
        return true;
    }
 
    // Check that the first comment is adjacent to the end of the group, the
    // last comment is adjacent to the candidate property, and that successive
    // comments are adjacent to each other.
    const comments = candidate.leadingComments;
 
    if (
        comments &&
        comments[0].loc.start.line - groupEndLine <= 1 &&
        candidateStartLine - last(comments).loc.end.line <= 1
    ) {
        for (let i = 1; i < comments.length; i++) {
            if (comments[i].loc.start.line - comments[i - 1].loc.end.line > 1) {
                return false;
            }
        }
        return true;
    }
 
    return false;
}
 
/**
 * Checks whether a node is contained on a single line.
 * @param {ASTNode} node AST Node being evaluated.
 * @returns {boolean} True if the node is a single line.
 */
function isSingleLine(node) {
    return (node.loc.end.line === node.loc.start.line);
}
 
/**
 * Initializes a single option property from the configuration with defaults for undefined values
 * @param {Object} toOptions Object to be initialized
 * @param {Object} fromOptions Object to be initialized from
 * @returns {Object} The object with correctly initialized options and values
 */
function initOptionProperty(toOptions, fromOptions) {
    toOptions.mode = fromOptions.mode || "strict";
 
    // Set value of beforeColon
    if (typeof fromOptions.beforeColon !== "undefined") {
        toOptions.beforeColon = +fromOptions.beforeColon;
    } else {
        toOptions.beforeColon = 0;
    }
 
    // Set value of afterColon
    if (typeof fromOptions.afterColon !== "undefined") {
        toOptions.afterColon = +fromOptions.afterColon;
    } else {
        toOptions.afterColon = 1;
    }
 
    // Set align if exists
    if (typeof fromOptions.align !== "undefined") {
        if (typeof fromOptions.align === "object") {
            toOptions.align = fromOptions.align;
        } else { // "string"
            toOptions.align = {
                on: fromOptions.align,
                mode: toOptions.mode,
                beforeColon: toOptions.beforeColon,
                afterColon: toOptions.afterColon
            };
        }
    }
 
    return toOptions;
}
 
/**
 * Initializes all the option values (singleLine, multiLine and align) from the configuration with defaults for undefined values
 * @param {Object} toOptions Object to be initialized
 * @param {Object} fromOptions Object to be initialized from
 * @returns {Object} The object with correctly initialized options and values
 */
function initOptions(toOptions, fromOptions) {
    if (typeof fromOptions.align === "object") {
 
        // Initialize the alignment configuration
        toOptions.align = initOptionProperty({}, fromOptions.align);
        toOptions.align.on = fromOptions.align.on || "colon";
        toOptions.align.mode = fromOptions.align.mode || "strict";
 
        toOptions.multiLine = initOptionProperty({}, (fromOptions.multiLine || fromOptions));
        toOptions.singleLine = initOptionProperty({}, (fromOptions.singleLine || fromOptions));
 
    } else { // string or undefined
        toOptions.multiLine = initOptionProperty({}, (fromOptions.multiLine || fromOptions));
        toOptions.singleLine = initOptionProperty({}, (fromOptions.singleLine || fromOptions));
 
        // If alignment options are defined in multiLine, pull them out into the general align configuration
        if (toOptions.multiLine.align) {
            toOptions.align = {
                on: toOptions.multiLine.align.on,
                mode: toOptions.multiLine.align.mode || toOptions.multiLine.mode,
                beforeColon: toOptions.multiLine.align.beforeColon,
                afterColon: toOptions.multiLine.align.afterColon
            };
        }
    }
 
    return toOptions;
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
const messages = {
    key: "{{error}} space after {{computed}}key '{{key}}'.",
    value: "{{error}} space before value for {{computed}}key '{{key}}'."
};
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent spacing between keys and values in object literal properties",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [{
            anyOf: [
                {
                    type: "object",
                    properties: {
                        align: {
                            anyOf: [
                                {
                                    enum: ["colon", "value"]
                                },
                                {
                                    type: "object",
                                    properties: {
                                        mode: {
                                            enum: ["strict", "minimum"]
                                        },
                                        on: {
                                            enum: ["colon", "value"]
                                        },
                                        beforeColon: {
                                            type: "boolean"
                                        },
                                        afterColon: {
                                            type: "boolean"
                                        }
                                    },
                                    additionalProperties: false
                                }
                            ]
                        },
                        mode: {
                            enum: ["strict", "minimum"]
                        },
                        beforeColon: {
                            type: "boolean"
                        },
                        afterColon: {
                            type: "boolean"
                        }
                    },
                    additionalProperties: false
                },
                {
                    type: "object",
                    properties: {
                        singleLine: {
                            type: "object",
                            properties: {
                                mode: {
                                    enum: ["strict", "minimum"]
                                },
                                beforeColon: {
                                    type: "boolean"
                                },
                                afterColon: {
                                    type: "boolean"
                                }
                            },
                            additionalProperties: false
                        },
                        multiLine: {
                            type: "object",
                            properties: {
                                align: {
                                    anyOf: [
                                        {
                                            enum: ["colon", "value"]
                                        },
                                        {
                                            type: "object",
                                            properties: {
                                                mode: {
                                                    enum: ["strict", "minimum"]
                                                },
                                                on: {
                                                    enum: ["colon", "value"]
                                                },
                                                beforeColon: {
                                                    type: "boolean"
                                                },
                                                afterColon: {
                                                    type: "boolean"
                                                }
                                            },
                                            additionalProperties: false
                                        }
                                    ]
                                },
                                mode: {
                                    enum: ["strict", "minimum"]
                                },
                                beforeColon: {
                                    type: "boolean"
                                },
                                afterColon: {
                                    type: "boolean"
                                }
                            },
                            additionalProperties: false
                        }
                    },
                    additionalProperties: false
                },
                {
                    type: "object",
                    properties: {
                        singleLine: {
                            type: "object",
                            properties: {
                                mode: {
                                    enum: ["strict", "minimum"]
                                },
                                beforeColon: {
                                    type: "boolean"
                                },
                                afterColon: {
                                    type: "boolean"
                                }
                            },
                            additionalProperties: false
                        },
                        multiLine: {
                            type: "object",
                            properties: {
                                mode: {
                                    enum: ["strict", "minimum"]
                                },
                                beforeColon: {
                                    type: "boolean"
                                },
                                afterColon: {
                                    type: "boolean"
                                }
                            },
                            additionalProperties: false
                        },
                        align: {
                            type: "object",
                            properties: {
                                mode: {
                                    enum: ["strict", "minimum"]
                                },
                                on: {
                                    enum: ["colon", "value"]
                                },
                                beforeColon: {
                                    type: "boolean"
                                },
                                afterColon: {
                                    type: "boolean"
                                }
                            },
                            additionalProperties: false
                        }
                    },
                    additionalProperties: false
                }
            ]
        }]
    },
 
    create(context) {
 
        /**
         * OPTIONS
         * "key-spacing": [2, {
         *     beforeColon: false,
         *     afterColon: true,
         *     align: "colon" // Optional, or "value"
         * }
         */
        const options = context.options[0] || {},
            ruleOptions = initOptions({}, options),
            multiLineOptions = ruleOptions.multiLine,
            singleLineOptions = ruleOptions.singleLine,
            alignmentOptions = ruleOptions.align || null;
 
        const sourceCode = context.getSourceCode();
 
        /**
         * Determines if the given property is key-value property.
         * @param {ASTNode} property Property node to check.
         * @returns {boolean} Whether the property is a key-value property.
         */
        function isKeyValueProperty(property) {
            return !(
                (property.method ||
                property.shorthand ||
                property.kind !== "init" || property.type !== "Property") // Could be "ExperimentalSpreadProperty" or "SpreadProperty"
            );
        }
 
        /**
         * Starting from the given a node (a property.key node here) looks forward
         * until it finds the last token before a colon punctuator and returns it.
         * @param {ASTNode} node The node to start looking from.
         * @returns {ASTNode} The last token before a colon punctuator.
         */
        function getLastTokenBeforeColon(node) {
            const colonToken = sourceCode.getTokenAfter(node, astUtils.isColonToken);
 
            return sourceCode.getTokenBefore(colonToken);
        }
 
        /**
         * Starting from the given a node (a property.key node here) looks forward
         * until it finds the colon punctuator and returns it.
         * @param {ASTNode} node The node to start looking from.
         * @returns {ASTNode} The colon punctuator.
         */
        function getNextColon(node) {
            return sourceCode.getTokenAfter(node, astUtils.isColonToken);
        }
 
        /**
         * Gets an object literal property's key as the identifier name or string value.
         * @param {ASTNode} property Property node whose key to retrieve.
         * @returns {string} The property's key.
         */
        function getKey(property) {
            const key = property.key;
 
            if (property.computed) {
                return sourceCode.getText().slice(key.range[0], key.range[1]);
            }
 
            return property.key.name || property.key.value;
        }
 
        /**
         * Reports an appropriately-formatted error if spacing is incorrect on one
         * side of the colon.
         * @param {ASTNode} property Key-value pair in an object literal.
         * @param {string} side Side being verified - either "key" or "value".
         * @param {string} whitespace Actual whitespace string.
         * @param {int} expected Expected whitespace length.
         * @param {string} mode Value of the mode as "strict" or "minimum"
         * @returns {void}
         */
        function report(property, side, whitespace, expected, mode) {
            const diff = whitespace.length - expected,
                nextColon = getNextColon(property.key),
                tokenBeforeColon = sourceCode.getTokenBefore(nextColon, { includeComments: true }),
                tokenAfterColon = sourceCode.getTokenAfter(nextColon, { includeComments: true }),
                isKeySide = side === "key",
                locStart = isKeySide ? tokenBeforeColon.loc.start : tokenAfterColon.loc.start,
                isExtra = diff > 0,
                diffAbs = Math.abs(diff),
                spaces = Array(diffAbs + 1).join(" ");
            let fix;
 
            if ((
                diff && mode === "strict" ||
                diff < 0 && mode === "minimum" ||
                diff > 0 && !expected && mode === "minimum") &&
                !(expected && containsLineTerminator(whitespace))
            ) {
                if (isExtra) {
                    let range;
 
                    // Remove whitespace
                    if (isKeySide) {
                        range = [tokenBeforeColon.end, tokenBeforeColon.end + diffAbs];
                    } else {
                        range = [tokenAfterColon.start - diffAbs, tokenAfterColon.start];
                    }
                    fix = function(fixer) {
                        return fixer.removeRange(range);
                    };
                } else {
 
                    // Add whitespace
                    if (isKeySide) {
                        fix = function(fixer) {
                            return fixer.insertTextAfter(tokenBeforeColon, spaces);
                        };
                    } else {
                        fix = function(fixer) {
                            return fixer.insertTextBefore(tokenAfterColon, spaces);
                        };
                    }
                }
 
                context.report({
                    node: property[side],
                    loc: locStart,
                    message: messages[side],
                    data: {
                        error: isExtra ? "Extra" : "Missing",
                        computed: property.computed ? "computed " : "",
                        key: getKey(property)
                    },
                    fix
                });
            }
        }
 
        /**
         * Gets the number of characters in a key, including quotes around string
         * keys and braces around computed property keys.
         * @param {ASTNode} property Property of on object literal.
         * @returns {int} Width of the key.
         */
        function getKeyWidth(property) {
            const startToken = sourceCode.getFirstToken(property);
            const endToken = getLastTokenBeforeColon(property.key);
 
            return endToken.range[1] - startToken.range[0];
        }
 
        /**
         * Gets the whitespace around the colon in an object literal property.
         * @param {ASTNode} property Property node from an object literal.
         * @returns {Object} Whitespace before and after the property's colon.
         */
        function getPropertyWhitespace(property) {
            const whitespace = /(\s*):(\s*)/.exec(sourceCode.getText().slice(
                property.key.range[1], property.value.range[0]
            ));
 
            if (whitespace) {
                return {
                    beforeColon: whitespace[1],
                    afterColon: whitespace[2]
                };
            }
            return null;
        }
 
        /**
         * Creates groups of properties.
         * @param  {ASTNode} node ObjectExpression node being evaluated.
         * @returns {Array.<ASTNode[]>} Groups of property AST node lists.
         */
        function createGroups(node) {
            if (node.properties.length === 1) {
                return [node.properties];
            }
 
            return node.properties.reduce((groups, property) => {
                const currentGroup = last(groups),
                    prev = last(currentGroup);
 
                if (!prev || continuesPropertyGroup(prev, property)) {
                    currentGroup.push(property);
                } else {
                    groups.push([property]);
                }
 
                return groups;
            }, [
                []
            ]);
        }
 
        /**
         * Verifies correct vertical alignment of a group of properties.
         * @param {ASTNode[]} properties List of Property AST nodes.
         * @returns {void}
         */
        function verifyGroupAlignment(properties) {
            const length = properties.length,
                widths = properties.map(getKeyWidth), // Width of keys, including quotes
                align = alignmentOptions.on; // "value" or "colon"
            let targetWidth = Math.max.apply(null, widths),
                beforeColon, afterColon, mode;
 
            if (alignmentOptions && length > 1) { // When aligning values within a group, use the alignment configuration.
                beforeColon = alignmentOptions.beforeColon;
                afterColon = alignmentOptions.afterColon;
                mode = alignmentOptions.mode;
            } else {
                beforeColon = multiLineOptions.beforeColon;
                afterColon = multiLineOptions.afterColon;
                mode = alignmentOptions.mode;
            }
 
            // Conditionally include one space before or after colon
            targetWidth += (align === "colon" ? beforeColon : afterColon);
 
            for (let i = 0; i < length; i++) {
                const property = properties[i];
                const whitespace = getPropertyWhitespace(property);
 
                if (whitespace) { // Object literal getters/setters lack a colon
                    const width = widths[i];
 
                    if (align === "value") {
                        report(property, "key", whitespace.beforeColon, beforeColon, mode);
                        report(property, "value", whitespace.afterColon, targetWidth - width, mode);
                    } else { // align = "colon"
                        report(property, "key", whitespace.beforeColon, targetWidth - width, mode);
                        report(property, "value", whitespace.afterColon, afterColon, mode);
                    }
                }
            }
        }
 
        /**
         * Verifies vertical alignment, taking into account groups of properties.
         * @param  {ASTNode} node ObjectExpression node being evaluated.
         * @returns {void}
         */
        function verifyAlignment(node) {
            createGroups(node).forEach(group => {
                verifyGroupAlignment(group.filter(isKeyValueProperty));
            });
        }
 
        /**
         * Verifies spacing of property conforms to specified options.
         * @param  {ASTNode} node Property node being evaluated.
         * @param {Object} lineOptions Configured singleLine or multiLine options
         * @returns {void}
         */
        function verifySpacing(node, lineOptions) {
            const actual = getPropertyWhitespace(node);
 
            if (actual) { // Object literal getters/setters lack colons
                report(node, "key", actual.beforeColon, lineOptions.beforeColon, lineOptions.mode);
                report(node, "value", actual.afterColon, lineOptions.afterColon, lineOptions.mode);
            }
        }
 
        /**
         * Verifies spacing of each property in a list.
         * @param  {ASTNode[]} properties List of Property AST nodes.
         * @returns {void}
         */
        function verifyListSpacing(properties) {
            const length = properties.length;
 
            for (let i = 0; i < length; i++) {
                verifySpacing(properties[i], singleLineOptions);
            }
        }
 
        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------
 
        if (alignmentOptions) { // Verify vertical alignment
 
            return {
                ObjectExpression(node) {
                    if (isSingleLine(node)) {
                        verifyListSpacing(node.properties.filter(isKeyValueProperty));
                    } else {
                        verifyAlignment(node);
                    }
                }
            };
 
        }
 
        // Obey beforeColon and afterColon in each property as configured
        return {
            Property(node) {
                verifySpacing(node, isSingleLine(node.parent) ? singleLineOptions : multiLineOptions);
            }
        };
 
 
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/keyword-spacing.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/keyword-spacing.js

Statements: 31.01% (40 / 129)      Branches: 0.94% (1 / 106)      Functions: 3.33% (1 / 30)      Lines: 31.01% (40 / 129)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586                      1             1 1 1 1 1 1 1 1     1 1 1 67                               1                   1               1                                     68               68                                         1                                                           1                                                           1                                                           1                                                           1                                                                                 1                         1                   1                       1                                   1                             1                             1                                   1                       1                       1                         1                       1                       1                                 1                                         1                         1                                                                                 1                                                                                                                  
/**
 * @fileoverview Rule to enforce spacing before and after keywords.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils"),
    keywords = require("../util/keywords");
 
//------------------------------------------------------------------------------
// Constants
//------------------------------------------------------------------------------
 
const PREV_TOKEN = /^[)\]}>]$/;
const NEXT_TOKEN = /^(?:[([{<~!]|\+\+?|--?)$/;
const PREV_TOKEN_M = /^[)\]}>*]$/;
const NEXT_TOKEN_M = /^[{*]$/;
const TEMPLATE_OPEN_PAREN = /\$\{$/;
const TEMPLATE_CLOSE_PAREN = /^\}/;
const CHECK_TYPE = /^(?:JSXElement|RegularExpression|String|Template)$/;
const KEYS = keywords.concat(["as", "async", "await", "from", "get", "let", "of", "set", "yield"]);
 
// check duplications.
(function() {
    KEYS.sort();
    for (let i = 1; i < KEYS.length; ++i) {
        Iif (KEYS[i] === KEYS[i - 1]) {
            throw new Error(`Duplication was found in the keyword list: ${KEYS[i]}`);
        }
    }
}());
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks whether or not a given token is a "Template" token ends with "${".
 *
 * @param {Token} token - A token to check.
 * @returns {boolean} `true` if the token is a "Template" token ends with "${".
 */
function isOpenParenOfTemplate(token) {
    return token.type === "Template" && TEMPLATE_OPEN_PAREN.test(token.value);
}
 
/**
 * Checks whether or not a given token is a "Template" token starts with "}".
 *
 * @param {Token} token - A token to check.
 * @returns {boolean} `true` if the token is a "Template" token starts with "}".
 */
function isCloseParenOfTemplate(token) {
    return token.type === "Template" && TEMPLATE_CLOSE_PAREN.test(token.value);
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent spacing before and after keywords",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                type: "object",
                properties: {
                    before: { type: "boolean" },
                    after: { type: "boolean" },
                    overrides: {
                        type: "object",
                        properties: KEYS.reduce((retv, key) => {
                            retv[key] = {
                                type: "object",
                                properties: {
                                    before: { type: "boolean" },
                                    after: { type: "boolean" }
                                },
                                additionalProperties: false
                            };
                            return retv;
                        }, {}),
                        additionalProperties: false
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        /**
         * Reports a given token if there are not space(s) before the token.
         *
         * @param {Token} token - A token to report.
         * @param {RegExp|undefined} pattern - Optional. A pattern of the previous
         *      token to check.
         * @returns {void}
         */
        function expectSpaceBefore(token, pattern) {
            pattern = pattern || PREV_TOKEN;
 
            const prevToken = sourceCode.getTokenBefore(token);
 
            if (prevToken &&
                (CHECK_TYPE.test(prevToken.type) || pattern.test(prevToken.value)) &&
                !isOpenParenOfTemplate(prevToken) &&
                astUtils.isTokenOnSameLine(prevToken, token) &&
                !sourceCode.isSpaceBetweenTokens(prevToken, token)
            ) {
                context.report({
                    loc: token.loc.start,
                    message: "Expected space(s) before \"{{value}}\".",
                    data: token,
                    fix(fixer) {
                        return fixer.insertTextBefore(token, " ");
                    }
                });
            }
        }
 
        /**
         * Reports a given token if there are space(s) before the token.
         *
         * @param {Token} token - A token to report.
         * @param {RegExp|undefined} pattern - Optional. A pattern of the previous
         *      token to check.
         * @returns {void}
         */
        function unexpectSpaceBefore(token, pattern) {
            pattern = pattern || PREV_TOKEN;
 
            const prevToken = sourceCode.getTokenBefore(token);
 
            if (prevToken &&
                (CHECK_TYPE.test(prevToken.type) || pattern.test(prevToken.value)) &&
                !isOpenParenOfTemplate(prevToken) &&
                astUtils.isTokenOnSameLine(prevToken, token) &&
                sourceCode.isSpaceBetweenTokens(prevToken, token)
            ) {
                context.report({
                    loc: token.loc.start,
                    message: "Unexpected space(s) before \"{{value}}\".",
                    data: token,
                    fix(fixer) {
                        return fixer.removeRange([prevToken.range[1], token.range[0]]);
                    }
                });
            }
        }
 
        /**
         * Reports a given token if there are not space(s) after the token.
         *
         * @param {Token} token - A token to report.
         * @param {RegExp|undefined} pattern - Optional. A pattern of the next
         *      token to check.
         * @returns {void}
         */
        function expectSpaceAfter(token, pattern) {
            pattern = pattern || NEXT_TOKEN;
 
            const nextToken = sourceCode.getTokenAfter(token);
 
            if (nextToken &&
                (CHECK_TYPE.test(nextToken.type) || pattern.test(nextToken.value)) &&
                !isCloseParenOfTemplate(nextToken) &&
                astUtils.isTokenOnSameLine(token, nextToken) &&
                !sourceCode.isSpaceBetweenTokens(token, nextToken)
            ) {
                context.report({
                    loc: token.loc.start,
                    message: "Expected space(s) after \"{{value}}\".",
                    data: token,
                    fix(fixer) {
                        return fixer.insertTextAfter(token, " ");
                    }
                });
            }
        }
 
        /**
         * Reports a given token if there are space(s) after the token.
         *
         * @param {Token} token - A token to report.
         * @param {RegExp|undefined} pattern - Optional. A pattern of the next
         *      token to check.
         * @returns {void}
         */
        function unexpectSpaceAfter(token, pattern) {
            pattern = pattern || NEXT_TOKEN;
 
            const nextToken = sourceCode.getTokenAfter(token);
 
            if (nextToken &&
                (CHECK_TYPE.test(nextToken.type) || pattern.test(nextToken.value)) &&
                !isCloseParenOfTemplate(nextToken) &&
                astUtils.isTokenOnSameLine(token, nextToken) &&
                sourceCode.isSpaceBetweenTokens(token, nextToken)
            ) {
                context.report({
                    loc: token.loc.start,
                    message: "Unexpected space(s) after \"{{value}}\".",
                    data: token,
                    fix(fixer) {
                        return fixer.removeRange([token.range[1], nextToken.range[0]]);
                    }
                });
            }
        }
 
        /**
         * Parses the option object and determines check methods for each keyword.
         *
         * @param {Object|undefined} options - The option object to parse.
         * @returns {Object} - Normalized option object.
         *      Keys are keywords (there are for every keyword).
         *      Values are instances of `{"before": function, "after": function}`.
         */
        function parseOptions(options) {
            const before = !options || options.before !== false;
            const after = !options || options.after !== false;
            const defaultValue = {
                before: before ? expectSpaceBefore : unexpectSpaceBefore,
                after: after ? expectSpaceAfter : unexpectSpaceAfter
            };
            const overrides = (options && options.overrides) || {};
            const retv = Object.create(null);
 
            for (let i = 0; i < KEYS.length; ++i) {
                const key = KEYS[i];
                const override = overrides[key];
 
                if (override) {
                    const thisBefore = ("before" in override) ? override.before : before;
                    const thisAfter = ("after" in override) ? override.after : after;
 
                    retv[key] = {
                        before: thisBefore ? expectSpaceBefore : unexpectSpaceBefore,
                        after: thisAfter ? expectSpaceAfter : unexpectSpaceAfter
                    };
                } else {
                    retv[key] = defaultValue;
                }
            }
 
            return retv;
        }
 
        const checkMethodMap = parseOptions(context.options[0]);
 
        /**
         * Reports a given token if usage of spacing followed by the token is
         * invalid.
         *
         * @param {Token} token - A token to report.
         * @param {RegExp|undefined} pattern - Optional. A pattern of the previous
         *      token to check.
         * @returns {void}
         */
        function checkSpacingBefore(token, pattern) {
            checkMethodMap[token.value].before(token, pattern);
        }
 
        /**
         * Reports a given token if usage of spacing preceded by the token is
         * invalid.
         *
         * @param {Token} token - A token to report.
         * @param {RegExp|undefined} pattern - Optional. A pattern of the next
         *      token to check.
         * @returns {void}
         */
        function checkSpacingAfter(token, pattern) {
            checkMethodMap[token.value].after(token, pattern);
        }
 
        /**
         * Reports a given token if usage of spacing around the token is invalid.
         *
         * @param {Token} token - A token to report.
         * @returns {void}
         */
        function checkSpacingAround(token) {
            checkSpacingBefore(token);
            checkSpacingAfter(token);
        }
 
        /**
         * Reports the first token of a given node if the first token is a keyword
         * and usage of spacing around the token is invalid.
         *
         * @param {ASTNode|null} node - A node to report.
         * @returns {void}
         */
        function checkSpacingAroundFirstToken(node) {
            const firstToken = node && sourceCode.getFirstToken(node);
 
            if (firstToken && firstToken.type === "Keyword") {
                checkSpacingAround(firstToken);
            }
        }
 
        /**
         * Reports the first token of a given node if the first token is a keyword
         * and usage of spacing followed by the token is invalid.
         *
         * This is used for unary operators (e.g. `typeof`), `function`, and `super`.
         * Other rules are handling usage of spacing preceded by those keywords.
         *
         * @param {ASTNode|null} node - A node to report.
         * @returns {void}
         */
        function checkSpacingBeforeFirstToken(node) {
            const firstToken = node && sourceCode.getFirstToken(node);
 
            if (firstToken && firstToken.type === "Keyword") {
                checkSpacingBefore(firstToken);
            }
        }
 
        /**
         * Reports the previous token of a given node if the token is a keyword and
         * usage of spacing around the token is invalid.
         *
         * @param {ASTNode|null} node - A node to report.
         * @returns {void}
         */
        function checkSpacingAroundTokenBefore(node) {
            if (node) {
                const token = sourceCode.getTokenBefore(node, astUtils.isKeywordToken);
 
                checkSpacingAround(token);
            }
        }
 
        /**
         * Reports `async` or `function` keywords of a given node if usage of
         * spacing around those keywords is invalid.
         *
         * @param {ASTNode} node - A node to report.
         * @returns {void}
         */
        function checkSpacingForFunction(node) {
            const firstToken = node && sourceCode.getFirstToken(node);
 
            if (firstToken &&
                ((firstToken.type === "Keyword" && firstToken.value === "function") ||
                firstToken.value === "async")
            ) {
                checkSpacingBefore(firstToken);
            }
        }
 
        /**
         * Reports `class` and `extends` keywords of a given node if usage of
         * spacing around those keywords is invalid.
         *
         * @param {ASTNode} node - A node to report.
         * @returns {void}
         */
        function checkSpacingForClass(node) {
            checkSpacingAroundFirstToken(node);
            checkSpacingAroundTokenBefore(node.superClass);
        }
 
        /**
         * Reports `if` and `else` keywords of a given node if usage of spacing
         * around those keywords is invalid.
         *
         * @param {ASTNode} node - A node to report.
         * @returns {void}
         */
        function checkSpacingForIfStatement(node) {
            checkSpacingAroundFirstToken(node);
            checkSpacingAroundTokenBefore(node.alternate);
        }
 
        /**
         * Reports `try`, `catch`, and `finally` keywords of a given node if usage
         * of spacing around those keywords is invalid.
         *
         * @param {ASTNode} node - A node to report.
         * @returns {void}
         */
        function checkSpacingForTryStatement(node) {
            checkSpacingAroundFirstToken(node);
            checkSpacingAroundFirstToken(node.handler);
            checkSpacingAroundTokenBefore(node.finalizer);
        }
 
        /**
         * Reports `do` and `while` keywords of a given node if usage of spacing
         * around those keywords is invalid.
         *
         * @param {ASTNode} node - A node to report.
         * @returns {void}
         */
        function checkSpacingForDoWhileStatement(node) {
            checkSpacingAroundFirstToken(node);
            checkSpacingAroundTokenBefore(node.test);
        }
 
        /**
         * Reports `for` and `in` keywords of a given node if usage of spacing
         * around those keywords is invalid.
         *
         * @param {ASTNode} node - A node to report.
         * @returns {void}
         */
        function checkSpacingForForInStatement(node) {
            checkSpacingAroundFirstToken(node);
            checkSpacingAroundTokenBefore(node.right);
        }
 
        /**
         * Reports `for` and `of` keywords of a given node if usage of spacing
         * around those keywords is invalid.
         *
         * @param {ASTNode} node - A node to report.
         * @returns {void}
         */
        function checkSpacingForForOfStatement(node) {
            checkSpacingAroundFirstToken(node);
            checkSpacingAround(sourceCode.getTokenBefore(node.right, astUtils.isNotOpeningParenToken));
        }
 
        /**
         * Reports `import`, `export`, `as`, and `from` keywords of a given node if
         * usage of spacing around those keywords is invalid.
         *
         * This rule handles the `*` token in module declarations.
         *
         *     import*as A from "./a"; /*error Expected space(s) after "import".
         *                               error Expected space(s) before "as".
         *
         * @param {ASTNode} node - A node to report.
         * @returns {void}
         */
        function checkSpacingForModuleDeclaration(node) {
            const firstToken = sourceCode.getFirstToken(node);
 
            checkSpacingBefore(firstToken, PREV_TOKEN_M);
            checkSpacingAfter(firstToken, NEXT_TOKEN_M);
 
            if (node.source) {
                const fromToken = sourceCode.getTokenBefore(node.source);
 
                checkSpacingBefore(fromToken, PREV_TOKEN_M);
                checkSpacingAfter(fromToken, NEXT_TOKEN_M);
            }
        }
 
        /**
         * Reports `as` keyword of a given node if usage of spacing around this
         * keyword is invalid.
         *
         * @param {ASTNode} node - A node to report.
         * @returns {void}
         */
        function checkSpacingForImportNamespaceSpecifier(node) {
            const asToken = sourceCode.getFirstToken(node, 1);
 
            checkSpacingBefore(asToken, PREV_TOKEN_M);
        }
 
        /**
         * Reports `static`, `get`, and `set` keywords of a given node if usage of
         * spacing around those keywords is invalid.
         *
         * @param {ASTNode} node - A node to report.
         * @returns {void}
         */
        function checkSpacingForProperty(node) {
            if (node.static) {
                checkSpacingAroundFirstToken(node);
            }
            if (node.kind === "get" ||
                node.kind === "set" ||
                (
                    (node.method || node.type === "MethodDefinition") &&
                    node.value.async
                )
            ) {
                const token = sourceCode.getTokenBefore(
                    node.key,
                    tok => {
                        switch (tok.value) {
                            case "get":
                            case "set":
                            case "async":
                                return true;
                            default:
                                return false;
                        }
                    }
                );
 
                if (!token) {
                    throw new Error("Failed to find token get, set, or async beside method name");
                }
 
 
                checkSpacingAround(token);
            }
        }
 
        /**
         * Reports `await` keyword of a given node if usage of spacing before
         * this keyword is invalid.
         *
         * @param {ASTNode} node - A node to report.
         * @returns {void}
         */
        function checkSpacingForAwaitExpression(node) {
            checkSpacingBefore(sourceCode.getFirstToken(node));
        }
 
        return {
 
            // Statements
            DebuggerStatement: checkSpacingAroundFirstToken,
            WithStatement: checkSpacingAroundFirstToken,
 
            // Statements - Control flow
            BreakStatement: checkSpacingAroundFirstToken,
            ContinueStatement: checkSpacingAroundFirstToken,
            ReturnStatement: checkSpacingAroundFirstToken,
            ThrowStatement: checkSpacingAroundFirstToken,
            TryStatement: checkSpacingForTryStatement,
 
            // Statements - Choice
            IfStatement: checkSpacingForIfStatement,
            SwitchStatement: checkSpacingAroundFirstToken,
            SwitchCase: checkSpacingAroundFirstToken,
 
            // Statements - Loops
            DoWhileStatement: checkSpacingForDoWhileStatement,
            ForInStatement: checkSpacingForForInStatement,
            ForOfStatement: checkSpacingForForOfStatement,
            ForStatement: checkSpacingAroundFirstToken,
            WhileStatement: checkSpacingAroundFirstToken,
 
            // Statements - Declarations
            ClassDeclaration: checkSpacingForClass,
            ExportNamedDeclaration: checkSpacingForModuleDeclaration,
            ExportDefaultDeclaration: checkSpacingAroundFirstToken,
            ExportAllDeclaration: checkSpacingForModuleDeclaration,
            FunctionDeclaration: checkSpacingForFunction,
            ImportDeclaration: checkSpacingForModuleDeclaration,
            VariableDeclaration: checkSpacingAroundFirstToken,
 
            // Expressions
            ArrowFunctionExpression: checkSpacingForFunction,
            AwaitExpression: checkSpacingForAwaitExpression,
            ClassExpression: checkSpacingForClass,
            FunctionExpression: checkSpacingForFunction,
            NewExpression: checkSpacingBeforeFirstToken,
            Super: checkSpacingBeforeFirstToken,
            ThisExpression: checkSpacingBeforeFirstToken,
            UnaryExpression: checkSpacingBeforeFirstToken,
            YieldExpression: checkSpacingBeforeFirstToken,
 
            // Others
            ImportNamespaceSpecifier: checkSpacingForImportNamespaceSpecifier,
            MethodDefinition: checkSpacingForProperty,
            Property: checkSpacingForProperty
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/line-comment-position.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/line-comment-position.js

Statements: 7.41% (2 / 27)      Branches: 0% (0 / 25)      Functions: 0% (0 / 2)      Lines: 7.41% (2 / 27)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113            1           1                                                                                                                                                                                                        
/**
 * @fileoverview Rule to enforce the position of line comments
 * @author Alberto Rodríguez
 */
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce position of line comments",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                oneOf: [
                    {
                        enum: ["above", "beside"]
                    },
                    {
                        type: "object",
                        properties: {
                            position: {
                                enum: ["above", "beside"]
                            },
                            ignorePattern: {
                                type: "string"
                            },
                            applyDefaultPatterns: {
                                type: "boolean"
                            },
                            applyDefaultIgnorePatterns: {
                                type: "boolean"
                            }
                        },
                        additionalProperties: false
                    }
                ]
            }
        ]
    },
 
    create(context) {
        const options = context.options[0];
 
        let above,
            ignorePattern,
            applyDefaultIgnorePatterns = true;
 
        if (!options || typeof options === "string") {
            above = !options || options === "above";
 
        } else {
            above = options.position === "above";
            ignorePattern = options.ignorePattern;
 
            if (options.hasOwnProperty("applyDefaultIgnorePatterns")) {
                applyDefaultIgnorePatterns = options.applyDefaultIgnorePatterns !== false;
            } else {
                applyDefaultIgnorePatterns = options.applyDefaultPatterns !== false;
            }
        }
 
        const defaultIgnoreRegExp = astUtils.COMMENTS_IGNORE_PATTERN;
        const fallThroughRegExp = /^\s*falls?\s?through/;
        const customIgnoreRegExp = new RegExp(ignorePattern);
        const sourceCode = context.getSourceCode();
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            LineComment(node) {
                if (applyDefaultIgnorePatterns && (defaultIgnoreRegExp.test(node.value) || fallThroughRegExp.test(node.value))) {
                    return;
                }
 
                if (ignorePattern && customIgnoreRegExp.test(node.value)) {
                    return;
                }
 
                const previous = sourceCode.getTokenBefore(node, { includeComments: true });
                const isOnSameLine = previous && previous.loc.end.line === node.loc.start.line;
 
                if (above) {
                    if (isOnSameLine) {
                        context.report({
                            node,
                            message: "Expected comment to be above code."
                        });
                    }
                } else {
                    if (!isOnSameLine) {
                        context.report({
                            node,
                            message: "Expected comment to be beside code."
                        });
                    }
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/linebreak-style.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/linebreak-style.js

Statements: 16.67% (3 / 18)      Branches: 0% (0 / 8)      Functions: 0% (0 / 4)      Lines: 16.67% (3 / 18)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98                      1           1                                                                     1                                                                                          
/**
 * @fileoverview Rule to enforce a single linebreak style.
 * @author Erik Mueller
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent linebreak style",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                enum: ["unix", "windows"]
            }
        ]
    },
 
    create(context) {
 
        const EXPECTED_LF_MSG = "Expected linebreaks to be 'LF' but found 'CRLF'.",
            EXPECTED_CRLF_MSG = "Expected linebreaks to be 'CRLF' but found 'LF'.";
 
        const sourceCode = context.getSourceCode();
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Builds a fix function that replaces text at the specified range in the source text.
         * @param {int[]} range The range to replace
         * @param {string} text The text to insert.
         * @returns {Function} Fixer function
         * @private
         */
        function createFix(range, text) {
            return function(fixer) {
                return fixer.replaceTextRange(range, text);
            };
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            Program: function checkForlinebreakStyle(node) {
                const linebreakStyle = context.options[0] || "unix",
                    expectedLF = linebreakStyle === "unix",
                    expectedLFChars = expectedLF ? "\n" : "\r\n",
                    source = sourceCode.getText(),
                    pattern = astUtils.createGlobalLinebreakMatcher();
                let match;
 
                let i = 0;
 
                while ((match = pattern.exec(source)) !== null) {
                    i++;
                    if (match[0] === expectedLFChars) {
                        continue;
                    }
 
                    const index = match.index;
                    const range = [index, index + match[0].length];
 
                    context.report({
                        node,
                        loc: {
                            line: i,
                            column: sourceCode.lines[i - 1].length
                        },
                        message: expectedLF ? EXPECTED_LF_MSG : EXPECTED_CRLF_MSG,
                        fix: createFix(range, expectedLFChars)
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/lines-around-comment.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/lines-around-comment.js

Statements: 16% (16 / 100)      Branches: 0% (0 / 111)      Functions: 0% (0 / 19)      Lines: 16.33% (16 / 98)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382                    1                       1                           1                               1                                                                                                                                                                           1                 1                                                             1                       1                                   1                                 1                 1                 1                 1                 1                 1                       1                                                                                                                                                                                                      
/**
 * @fileoverview Enforces empty lines around comments.
 * @author Jamund Ferguson
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const lodash = require("lodash"),
    astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Return an array with with any line numbers that are empty.
 * @param {Array} lines An array of each line of the file.
 * @returns {Array} An array of line numbers.
 */
function getEmptyLineNums(lines) {
    const emptyLines = lines.map((line, i) => ({
        code: line.trim(),
        num: i + 1
    })).filter(line => !line.code).map(line => line.num);
 
    return emptyLines;
}
 
/**
 * Return an array with with any line numbers that contain comments.
 * @param {Array} comments An array of comment nodes.
 * @returns {Array} An array of line numbers.
 */
function getCommentLineNums(comments) {
    const lines = [];
 
    comments.forEach(token => {
        const start = token.loc.start.line;
        const end = token.loc.end.line;
 
        lines.push(start, end);
    });
    return lines;
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require empty lines around comments",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                type: "object",
                properties: {
                    beforeBlockComment: {
                        type: "boolean"
                    },
                    afterBlockComment: {
                        type: "boolean"
                    },
                    beforeLineComment: {
                        type: "boolean"
                    },
                    afterLineComment: {
                        type: "boolean"
                    },
                    allowBlockStart: {
                        type: "boolean"
                    },
                    allowBlockEnd: {
                        type: "boolean"
                    },
                    allowObjectStart: {
                        type: "boolean"
                    },
                    allowObjectEnd: {
                        type: "boolean"
                    },
                    allowArrayStart: {
                        type: "boolean"
                    },
                    allowArrayEnd: {
                        type: "boolean"
                    },
                    ignorePattern: {
                        type: "string"
                    },
                    applyDefaultIgnorePatterns: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        const options = context.options[0] ? Object.assign({}, context.options[0]) : {};
        const ignorePattern = options.ignorePattern;
        const defaultIgnoreRegExp = astUtils.COMMENTS_IGNORE_PATTERN;
        const customIgnoreRegExp = new RegExp(ignorePattern);
        const applyDefaultIgnorePatterns = options.applyDefaultIgnorePatterns !== false;
 
 
        options.beforeLineComment = options.beforeLineComment || false;
        options.afterLineComment = options.afterLineComment || false;
        options.beforeBlockComment = typeof options.beforeBlockComment !== "undefined" ? options.beforeBlockComment : true;
        options.afterBlockComment = options.afterBlockComment || false;
        options.allowBlockStart = options.allowBlockStart || false;
        options.allowBlockEnd = options.allowBlockEnd || false;
 
        const sourceCode = context.getSourceCode();
 
        const lines = sourceCode.lines,
            numLines = lines.length + 1,
            comments = sourceCode.getAllComments(),
            commentLines = getCommentLineNums(comments),
            emptyLines = getEmptyLineNums(lines),
            commentAndEmptyLines = commentLines.concat(emptyLines);
 
        /**
         * Returns whether or not a token is a comment node type
         * @param {Token} token The token to check
         * @returns {boolean} True if the token is a comment node
         */
        function isCommentNodeType(token) {
            return token && (token.type === "Block" || token.type === "Line");
        }
 
        /**
         * Returns whether or not comments are on lines starting with or ending with code
         * @param {ASTNode} node The comment node to check.
         * @returns {boolean} True if the comment is not alone.
         */
        function codeAroundComment(node) {
            let token;
 
            token = node;
            do {
                token = sourceCode.getTokenBefore(token, { includeComments: true });
            } while (isCommentNodeType(token));
 
            if (token && astUtils.isTokenOnSameLine(token, node)) {
                return true;
            }
 
            token = node;
            do {
                token = sourceCode.getTokenAfter(token, { includeComments: true });
            } while (isCommentNodeType(token));
 
            if (token && astUtils.isTokenOnSameLine(node, token)) {
                return true;
            }
 
            return false;
        }
 
        /**
         * Returns whether or not comments are inside a node type or not.
         * @param {ASTNode} node The Comment node.
         * @param {ASTNode} parent The Comment parent node.
         * @param {string} nodeType The parent type to check against.
         * @returns {boolean} True if the comment is inside nodeType.
         */
        function isCommentInsideNodeType(node, parent, nodeType) {
            return parent.type === nodeType ||
                (parent.body && parent.body.type === nodeType) ||
                (parent.consequent && parent.consequent.type === nodeType);
        }
 
        /**
         * Returns whether or not comments are at the parent start or not.
         * @param {ASTNode} node The Comment node.
         * @param {string} nodeType The parent type to check against.
         * @returns {boolean} True if the comment is at parent start.
         */
        function isCommentAtParentStart(node, nodeType) {
            const ancestors = context.getAncestors();
            let parent;
 
            if (ancestors.length) {
                parent = ancestors.pop();
            }
 
            return parent && isCommentInsideNodeType(node, parent, nodeType) &&
                    node.loc.start.line - parent.loc.start.line === 1;
        }
 
        /**
         * Returns whether or not comments are at the parent end or not.
         * @param {ASTNode} node The Comment node.
         * @param {string} nodeType The parent type to check against.
         * @returns {boolean} True if the comment is at parent end.
         */
        function isCommentAtParentEnd(node, nodeType) {
            const ancestors = context.getAncestors();
            let parent;
 
            if (ancestors.length) {
                parent = ancestors.pop();
            }
 
            return parent && isCommentInsideNodeType(node, parent, nodeType) &&
                    parent.loc.end.line - node.loc.end.line === 1;
        }
 
        /**
         * Returns whether or not comments are at the block start or not.
         * @param {ASTNode} node The Comment node.
         * @returns {boolean} True if the comment is at block start.
         */
        function isCommentAtBlockStart(node) {
            return isCommentAtParentStart(node, "ClassBody") || isCommentAtParentStart(node, "BlockStatement") || isCommentAtParentStart(node, "SwitchCase");
        }
 
        /**
         * Returns whether or not comments are at the block end or not.
         * @param {ASTNode} node The Comment node.
         * @returns {boolean} True if the comment is at block end.
         */
        function isCommentAtBlockEnd(node) {
            return isCommentAtParentEnd(node, "ClassBody") || isCommentAtParentEnd(node, "BlockStatement") || isCommentAtParentEnd(node, "SwitchCase") || isCommentAtParentEnd(node, "SwitchStatement");
        }
 
        /**
         * Returns whether or not comments are at the object start or not.
         * @param {ASTNode} node The Comment node.
         * @returns {boolean} True if the comment is at object start.
         */
        function isCommentAtObjectStart(node) {
            return isCommentAtParentStart(node, "ObjectExpression") || isCommentAtParentStart(node, "ObjectPattern");
        }
 
        /**
         * Returns whether or not comments are at the object end or not.
         * @param {ASTNode} node The Comment node.
         * @returns {boolean} True if the comment is at object end.
         */
        function isCommentAtObjectEnd(node) {
            return isCommentAtParentEnd(node, "ObjectExpression") || isCommentAtParentEnd(node, "ObjectPattern");
        }
 
        /**
         * Returns whether or not comments are at the array start or not.
         * @param {ASTNode} node The Comment node.
         * @returns {boolean} True if the comment is at array start.
         */
        function isCommentAtArrayStart(node) {
            return isCommentAtParentStart(node, "ArrayExpression") || isCommentAtParentStart(node, "ArrayPattern");
        }
 
        /**
         * Returns whether or not comments are at the array end or not.
         * @param {ASTNode} node The Comment node.
         * @returns {boolean} True if the comment is at array end.
         */
        function isCommentAtArrayEnd(node) {
            return isCommentAtParentEnd(node, "ArrayExpression") || isCommentAtParentEnd(node, "ArrayPattern");
        }
 
        /**
         * Checks if a comment node has lines around it (ignores inline comments)
         * @param {ASTNode} node The Comment node.
         * @param {Object} opts Options to determine the newline.
         * @param {boolean} opts.after Should have a newline after this line.
         * @param {boolean} opts.before Should have a newline before this line.
         * @returns {void}
         */
        function checkForEmptyLine(node, opts) {
            if (applyDefaultIgnorePatterns && defaultIgnoreRegExp.test(node.value)) {
                return;
            }
 
            if (ignorePattern && customIgnoreRegExp.test(node.value)) {
                return;
            }
 
            let after = opts.after,
                before = opts.before;
 
            const prevLineNum = node.loc.start.line - 1,
                nextLineNum = node.loc.end.line + 1,
                commentIsNotAlone = codeAroundComment(node);
 
            const blockStartAllowed = options.allowBlockStart && isCommentAtBlockStart(node),
                blockEndAllowed = options.allowBlockEnd && isCommentAtBlockEnd(node),
                objectStartAllowed = options.allowObjectStart && isCommentAtObjectStart(node),
                objectEndAllowed = options.allowObjectEnd && isCommentAtObjectEnd(node),
                arrayStartAllowed = options.allowArrayStart && isCommentAtArrayStart(node),
                arrayEndAllowed = options.allowArrayEnd && isCommentAtArrayEnd(node);
 
            const exceptionStartAllowed = blockStartAllowed || objectStartAllowed || arrayStartAllowed;
            const exceptionEndAllowed = blockEndAllowed || objectEndAllowed || arrayEndAllowed;
 
            // ignore top of the file and bottom of the file
            if (prevLineNum < 1) {
                before = false;
            }
            if (nextLineNum >= numLines) {
                after = false;
            }
 
            // we ignore all inline comments
            if (commentIsNotAlone) {
                return;
            }
 
            const previousTokenOrComment = sourceCode.getTokenBefore(node, { includeComments: true });
            const nextTokenOrComment = sourceCode.getTokenAfter(node, { includeComments: true });
 
            // check for newline before
            if (!exceptionStartAllowed && before && !lodash.includes(commentAndEmptyLines, prevLineNum) &&
                    !(isCommentNodeType(previousTokenOrComment) && astUtils.isTokenOnSameLine(previousTokenOrComment, node))) {
                const lineStart = node.range[0] - node.loc.start.column;
                const range = [lineStart, lineStart];
 
                context.report({
                    node,
                    message: "Expected line before comment.",
                    fix(fixer) {
                        return fixer.insertTextBeforeRange(range, "\n");
                    }
                });
            }
 
            // check for newline after
            if (!exceptionEndAllowed && after && !lodash.includes(commentAndEmptyLines, nextLineNum) &&
                    !(isCommentNodeType(nextTokenOrComment) && astUtils.isTokenOnSameLine(node, nextTokenOrComment))) {
                context.report({
                    node,
                    message: "Expected line after comment.",
                    fix(fixer) {
                        return fixer.insertTextAfter(node, "\n");
                    }
                });
            }
 
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
 
            LineComment(node) {
                if (options.beforeLineComment || options.afterLineComment) {
                    checkForEmptyLine(node, {
                        after: options.afterLineComment,
                        before: options.beforeLineComment
                    });
                }
            },
 
            BlockComment(node) {
                if (options.beforeBlockComment || options.afterBlockComment) {
                    checkForEmptyLine(node, {
                        after: options.afterBlockComment,
                        before: options.beforeBlockComment
                    });
                }
            }
 
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/lines-around-directive.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/lines-around-directive.js

Statements: 15.22% (7 / 46)      Branches: 0% (0 / 56)      Functions: 0% (0 / 7)      Lines: 15.22% (7 / 46)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193              1           1                                                                                         1                           1                           1                           1                                                 1                                                                                                                                      
/**
 * @fileoverview Require or disallow newlines around directives.
 * @author Kai Cataldo
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require or disallow newlines around directives",
            category: "Stylistic Issues",
            recommended: false
        },
        schema: [{
            oneOf: [
                {
                    enum: ["always", "never"]
                },
                {
                    type: "object",
                    properties: {
                        before: {
                            enum: ["always", "never"]
                        },
                        after: {
                            enum: ["always", "never"]
                        }
                    },
                    additionalProperties: false,
                    minProperties: 2
                }
            ]
        }],
        fixable: "whitespace"
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
        const config = context.options[0] || "always";
        const expectLineBefore = typeof config === "string" ? config : config.before;
        const expectLineAfter = typeof config === "string" ? config : config.after;
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Check if node is preceded by a blank newline.
         * @param {ASTNode} node Node to check.
         * @returns {boolean} Whether or not the passed in node is preceded by a blank newline.
         */
        function hasNewlineBefore(node) {
            const tokenBefore = sourceCode.getTokenBefore(node, { includeComments: true });
            const tokenLineBefore = tokenBefore ? tokenBefore.loc.end.line : 0;
 
            return node.loc.start.line - tokenLineBefore >= 2;
        }
 
        /**
        * Gets the last token of a node that is on the same line as the rest of the node.
        * This will usually be the last token of the node, but it will be the second-to-last token if the node has a trailing
        * semicolon on a different line.
        * @param {ASTNode} node A directive node
        * @returns {Token} The last token of the node on the line
        */
        function getLastTokenOnLine(node) {
            const lastToken = sourceCode.getLastToken(node);
            const secondToLastToken = sourceCode.getTokenBefore(lastToken);
 
            return astUtils.isSemicolonToken(lastToken) && lastToken.loc.start.line > secondToLastToken.loc.end.line
                ? secondToLastToken
                : lastToken;
        }
 
        /**
         * Check if node is followed by a blank newline.
         * @param {ASTNode} node Node to check.
         * @returns {boolean} Whether or not the passed in node is followed by a blank newline.
         */
        function hasNewlineAfter(node) {
            const lastToken = getLastTokenOnLine(node);
            const tokenAfter = sourceCode.getTokenAfter(lastToken, { includeComments: true });
 
            return tokenAfter.loc.start.line - lastToken.loc.end.line >= 2;
        }
 
        /**
         * Report errors for newlines around directives.
         * @param {ASTNode} node Node to check.
         * @param {string} location Whether the error was found before or after the directive.
         * @param {boolean} expected Whether or not a newline was expected or unexpected.
         * @returns {void}
         */
        function reportError(node, location, expected) {
            context.report({
                node,
                message: "{{expected}} newline {{location}} \"{{value}}\" directive.",
                data: {
                    expected: expected ? "Expected" : "Unexpected",
                    value: node.expression.value,
                    location
                },
                fix(fixer) {
                    const lastToken = getLastTokenOnLine(node);
 
                    if (expected) {
                        return location === "before" ? fixer.insertTextBefore(node, "\n") : fixer.insertTextAfter(lastToken, "\n");
                    }
                    return fixer.removeRange(location === "before" ? [node.range[0] - 1, node.range[0]] : [lastToken.range[1], lastToken.range[1] + 1]);
                }
            });
        }
 
        /**
         * Check lines around directives in node
         * @param {ASTNode} node - node to check
         * @returns {void}
         */
        function checkDirectives(node) {
            const directives = astUtils.getDirectivePrologue(node);
 
            if (!directives.length) {
                return;
            }
 
            const firstDirective = directives[0];
            const hasTokenOrCommentBefore = !!sourceCode.getTokenBefore(firstDirective, { includeComments: true });
 
            // Only check before the first directive if it is preceded by a comment or if it is at the top of
            // the file and expectLineBefore is set to "never". This is to not force a newline at the top of
            // the file if there are no comments as well as for compatibility with padded-blocks.
            if (
                firstDirective.leadingComments && firstDirective.leadingComments.length ||
 
                // Shebangs are not added to leading comments but are accounted for by the following.
                node.type === "Program" && hasTokenOrCommentBefore
            ) {
                if (expectLineBefore === "always" && !hasNewlineBefore(firstDirective)) {
                    reportError(firstDirective, "before", true);
                }
 
                if (expectLineBefore === "never" && hasNewlineBefore(firstDirective)) {
                    reportError(firstDirective, "before", false);
                }
            } else if (
                node.type === "Program" &&
                expectLineBefore === "never" &&
                !hasTokenOrCommentBefore &&
                hasNewlineBefore(firstDirective)
            ) {
                reportError(firstDirective, "before", false);
            }
 
            const lastDirective = directives[directives.length - 1];
            const statements = node.type === "Program" ? node.body : node.body.body;
 
            // Do not check after the last directive if the body only
            // contains a directive prologue and isn't followed by a comment to ensure
            // this rule behaves well with padded-blocks.
            if (lastDirective === statements[statements.length - 1] && !lastDirective.trailingComments) {
                return;
            }
 
            if (expectLineAfter === "always" && !hasNewlineAfter(lastDirective)) {
                reportError(lastDirective, "after", true);
            }
 
            if (expectLineAfter === "never" && hasNewlineAfter(lastDirective)) {
                reportError(lastDirective, "after", false);
            }
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            Program: checkDirectives,
            FunctionDeclaration: checkDirectives,
            FunctionExpression: checkDirectives,
            ArrowFunctionExpression: checkDirectives
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/max-depth.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/max-depth.js

Statements: 22.73% (5 / 22)      Branches: 0% (0 / 16)      Functions: 0% (0 / 6)      Lines: 22.73% (5 / 22)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150                      1                                                                                                                     1                 1                   1                         1                                                                                              
/**
 * @fileoverview A rule to set the maximum depth block can be nested in a function.
 * @author Ian Christian Myers
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce a maximum depth that blocks can be nested",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                oneOf: [
                    {
                        type: "integer",
                        minimum: 0
                    },
                    {
                        type: "object",
                        properties: {
                            maximum: {
                                type: "integer",
                                minimum: 0
                            },
                            max: {
                                type: "integer",
                                minimum: 0
                            }
                        },
                        additionalProperties: false
                    }
                ]
            }
        ]
    },
 
    create(context) {
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        const functionStack = [],
            option = context.options[0];
        let maxDepth = 4;
 
        if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") {
            maxDepth = option.maximum;
        }
        if (typeof option === "object" && option.hasOwnProperty("max") && typeof option.max === "number") {
            maxDepth = option.max;
        }
        if (typeof option === "number") {
            maxDepth = option;
        }
 
        /**
         * When parsing a new function, store it in our function stack
         * @returns {void}
         * @private
         */
        function startFunction() {
            functionStack.push(0);
        }
 
        /**
         * When parsing is done then pop out the reference
         * @returns {void}
         * @private
         */
        function endFunction() {
            functionStack.pop();
        }
 
        /**
         * Save the block and Evaluate the node
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function pushBlock(node) {
            const len = ++functionStack[functionStack.length - 1];
 
            if (len > maxDepth) {
                context.report({ node, message: "Blocks are nested too deeply ({{depth}}).", data: { depth: len } });
            }
        }
 
        /**
         * Pop the saved block
         * @returns {void}
         * @private
         */
        function popBlock() {
            functionStack[functionStack.length - 1]--;
        }
 
        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------
 
        return {
            Program: startFunction,
            FunctionDeclaration: startFunction,
            FunctionExpression: startFunction,
            ArrowFunctionExpression: startFunction,
 
            IfStatement(node) {
                if (node.parent.type !== "IfStatement") {
                    pushBlock(node);
                }
            },
            SwitchStatement: pushBlock,
            TryStatement: pushBlock,
            DoWhileStatement: pushBlock,
            WhileStatement: pushBlock,
            WithStatement: pushBlock,
            ForStatement: pushBlock,
            ForInStatement: pushBlock,
            ForOfStatement: pushBlock,
 
            "IfStatement:exit": popBlock,
            "SwitchStatement:exit": popBlock,
            "TryStatement:exit": popBlock,
            "DoWhileStatement:exit": popBlock,
            "WhileStatement:exit": popBlock,
            "WithStatement:exit": popBlock,
            "ForStatement:exit": popBlock,
            "ForInStatement:exit": popBlock,
            "ForOfStatement:exit": popBlock,
 
            "FunctionDeclaration:exit": endFunction,
            "FunctionExpression:exit": endFunction,
            "ArrowFunctionExpression:exit": endFunction,
            "Program:exit": endFunction
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/max-len.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/max-len.js

Statements: 17.11% (13 / 76)      Branches: 0% (0 / 80)      Functions: 0% (0 / 11)      Lines: 17.81% (13 / 73)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365                      1                                                                               1                           1                                                                         1                                                                                                           1                         1                                   1                             1                       1                 1                   1                         1                         1                                                                                                                                                                                                                  
/**
 * @fileoverview Rule to check for max length on a line.
 * @author Matt DuVall <http://www.mattduvall.com>
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Constants
//------------------------------------------------------------------------------
 
const OPTIONS_SCHEMA = {
    type: "object",
    properties: {
        code: {
            type: "integer",
            minimum: 0
        },
        comments: {
            type: "integer",
            minimum: 0
        },
        tabWidth: {
            type: "integer",
            minimum: 0
        },
        ignorePattern: {
            type: "string"
        },
        ignoreComments: {
            type: "boolean"
        },
        ignoreStrings: {
            type: "boolean"
        },
        ignoreUrls: {
            type: "boolean"
        },
        ignoreTemplateLiterals: {
            type: "boolean"
        },
        ignoreRegExpLiterals: {
            type: "boolean"
        },
        ignoreTrailingComments: {
            type: "boolean"
        }
    },
    additionalProperties: false
};
 
const OPTIONS_OR_INTEGER_SCHEMA = {
    anyOf: [
        OPTIONS_SCHEMA,
        {
            type: "integer",
            minimum: 0
        }
    ]
};
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce a maximum line length",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            OPTIONS_OR_INTEGER_SCHEMA,
            OPTIONS_OR_INTEGER_SCHEMA,
            OPTIONS_SCHEMA
        ]
    },
 
    create(context) {
 
        /*
         * Inspired by http://tools.ietf.org/html/rfc3986#appendix-B, however:
         * - They're matching an entire string that we know is a URI
         * - We're matching part of a string where we think there *might* be a URL
         * - We're only concerned about URLs, as picking out any URI would cause
         *   too many false positives
         * - We don't care about matching the entire URL, any small segment is fine
         */
        const URL_REGEXP = /[^:/?#]:\/\/[^?#]/;
 
        const sourceCode = context.getSourceCode();
 
        /**
         * Computes the length of a line that may contain tabs. The width of each
         * tab will be the number of spaces to the next tab stop.
         * @param {string} line The line.
         * @param {int} tabWidth The width of each tab stop in spaces.
         * @returns {int} The computed line length.
         * @private
         */
        function computeLineLength(line, tabWidth) {
            let extraCharacterCount = 0;
 
            line.replace(/\t/g, (match, offset) => {
                const totalOffset = offset + extraCharacterCount,
                    previousTabStopOffset = tabWidth ? totalOffset % tabWidth : 0,
                    spaceCount = tabWidth - previousTabStopOffset;
 
                extraCharacterCount += spaceCount - 1;  // -1 for the replaced tab
            });
            return Array.from(line).length + extraCharacterCount;
        }
 
        // The options object must be the last option specified…
        const lastOption = context.options[context.options.length - 1];
        const options = typeof lastOption === "object" ? Object.create(lastOption) : {};
 
        // …but max code length…
        if (typeof context.options[0] === "number") {
            options.code = context.options[0];
        }
 
        // …and tabWidth can be optionally specified directly as integers.
        if (typeof context.options[1] === "number") {
            options.tabWidth = context.options[1];
        }
 
        const maxLength = options.code || 80,
            tabWidth = options.tabWidth || 4,
            ignoreComments = options.ignoreComments || false,
            ignoreStrings = options.ignoreStrings || false,
            ignoreTemplateLiterals = options.ignoreTemplateLiterals || false,
            ignoreRegExpLiterals = options.ignoreRegExpLiterals || false,
            ignoreTrailingComments = options.ignoreTrailingComments || options.ignoreComments || false,
            ignoreUrls = options.ignoreUrls || false,
            maxCommentLength = options.comments;
        let ignorePattern = options.ignorePattern || null;
 
        if (ignorePattern) {
            ignorePattern = new RegExp(ignorePattern);
        }
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Tells if a given comment is trailing: it starts on the current line and
         * extends to or past the end of the current line.
         * @param {string} line The source line we want to check for a trailing comment on
         * @param {number} lineNumber The one-indexed line number for line
         * @param {ASTNode} comment The comment to inspect
         * @returns {boolean} If the comment is trailing on the given line
         */
        function isTrailingComment(line, lineNumber, comment) {
            return comment &&
                (comment.loc.start.line === lineNumber && lineNumber <= comment.loc.end.line) &&
                (comment.loc.end.line > lineNumber || comment.loc.end.column === line.length);
        }
 
        /**
         * Tells if a comment encompasses the entire line.
         * @param {string} line The source line with a trailing comment
         * @param {number} lineNumber The one-indexed line number this is on
         * @param {ASTNode} comment The comment to remove
         * @returns {boolean} If the comment covers the entire line
         */
        function isFullLineComment(line, lineNumber, comment) {
            const start = comment.loc.start,
                end = comment.loc.end,
                isFirstTokenOnLine = !line.slice(0, comment.loc.start.column).trim();
 
            return comment &&
                (start.line < lineNumber || (start.line === lineNumber && isFirstTokenOnLine)) &&
                (end.line > lineNumber || (end.line === lineNumber && end.column === line.length));
        }
 
        /**
         * Gets the line after the comment and any remaining trailing whitespace is
         * stripped.
         * @param {string} line The source line with a trailing comment
         * @param {number} lineNumber The one-indexed line number this is on
         * @param {ASTNode} comment The comment to remove
         * @returns {string} Line without comment and trailing whitepace
         */
        function stripTrailingComment(line, lineNumber, comment) {
 
            // loc.column is zero-indexed
            return line.slice(0, comment.loc.start.column).replace(/\s+$/, "");
        }
 
        /**
         * Ensure that an array exists at [key] on `object`, and add `value` to it.
         *
         * @param {Object} object the object to mutate
         * @param {string} key the object's key
         * @param {*} value the value to add
         * @returns {void}
         * @private
         */
        function ensureArrayAndPush(object, key, value) {
            if (!Array.isArray(object[key])) {
                object[key] = [];
            }
            object[key].push(value);
        }
 
        /**
         * Retrieves an array containing all strings (" or ') in the source code.
         *
         * @returns {ASTNode[]} An array of string nodes.
         */
        function getAllStrings() {
            return sourceCode.ast.tokens.filter(token => token.type === "String");
        }
 
        /**
         * Retrieves an array containing all template literals in the source code.
         *
         * @returns {ASTNode[]} An array of template literal nodes.
         */
        function getAllTemplateLiterals() {
            return sourceCode.ast.tokens.filter(token => token.type === "Template");
        }
 
 
        /**
         * Retrieves an array containing all RegExp literals in the source code.
         *
         * @returns {ASTNode[]} An array of RegExp literal nodes.
         */
        function getAllRegExpLiterals() {
            return sourceCode.ast.tokens.filter(token => token.type === "RegularExpression");
        }
 
 
        /**
         * A reducer to group an AST node by line number, both start and end.
         *
         * @param {Object} acc the accumulator
         * @param {ASTNode} node the AST node in question
         * @returns {Object} the modified accumulator
         * @private
         */
        function groupByLineNumber(acc, node) {
            for (let i = node.loc.start.line; i <= node.loc.end.line; ++i) {
                ensureArrayAndPush(acc, i, node);
            }
            return acc;
        }
 
        /**
         * Check the program for max length
         * @param {ASTNode} node Node to examine
         * @returns {void}
         * @private
         */
        function checkProgramForMaxLength(node) {
 
            // split (honors line-ending)
            const lines = sourceCode.lines,
 
                // list of comments to ignore
                comments = ignoreComments || maxCommentLength || ignoreTrailingComments ? sourceCode.getAllComments() : [];
 
                // we iterate over comments in parallel with the lines
            let commentsIndex = 0;
 
            const strings = getAllStrings(sourceCode);
            const stringsByLine = strings.reduce(groupByLineNumber, {});
 
            const templateLiterals = getAllTemplateLiterals(sourceCode);
            const templateLiteralsByLine = templateLiterals.reduce(groupByLineNumber, {});
 
            const regExpLiterals = getAllRegExpLiterals(sourceCode);
            const regExpLiteralsByLine = regExpLiterals.reduce(groupByLineNumber, {});
 
            lines.forEach((line, i) => {
 
                // i is zero-indexed, line numbers are one-indexed
                const lineNumber = i + 1;
 
                /*
                 * if we're checking comment length; we need to know whether this
                 * line is a comment
                 */
                let lineIsComment = false;
 
                /*
                 * We can short-circuit the comment checks if we're already out of
                 * comments to check.
                 */
                if (commentsIndex < comments.length) {
                    let comment = null;
 
                    // iterate over comments until we find one past the current line
                    do {
                        comment = comments[++commentsIndex];
                    } while (comment && comment.loc.start.line <= lineNumber);
 
                    // and step back by one
                    comment = comments[--commentsIndex];
 
                    if (isFullLineComment(line, lineNumber, comment)) {
                        lineIsComment = true;
                    } else if (ignoreTrailingComments && isTrailingComment(line, lineNumber, comment)) {
                        line = stripTrailingComment(line, lineNumber, comment);
                    }
                }
                if (ignorePattern && ignorePattern.test(line) ||
                    ignoreUrls && URL_REGEXP.test(line) ||
                    ignoreStrings && stringsByLine[lineNumber] ||
                    ignoreTemplateLiterals && templateLiteralsByLine[lineNumber] ||
                    ignoreRegExpLiterals && regExpLiteralsByLine[lineNumber]
                ) {
 
                    // ignore this line
                    return;
                }
 
                const lineLength = computeLineLength(line, tabWidth);
 
                if (lineIsComment && ignoreComments) {
                    return;
                }
 
                if (lineIsComment && lineLength > maxCommentLength) {
                    context.report({
                        node,
                        loc: { line: lineNumber, column: 0 },
                        message: "Line {{lineNumber}} exceeds the maximum comment line length of {{maxCommentLength}}.",
                        data: {
                            lineNumber: i + 1,
                            maxCommentLength
                        }
                    });
                } else if (lineLength > maxLength) {
                    context.report({
                        node,
                        loc: { line: lineNumber, column: 0 },
                        message: "Line {{lineNumber}} exceeds the maximum line length of {{maxLength}}.",
                        data: {
                            lineNumber: i + 1,
                            maxLength
                        }
                    });
                }
            });
        }
 
 
        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------
 
        return {
            Program: checkProgramForMaxLength
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/max-lines.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/max-lines.js

Statements: 11.11% (5 / 45)      Branches: 0% (0 / 30)      Functions: 0% (0 / 4)      Lines: 12.2% (5 / 41)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146                    1 1           1                                                                                                                   1                 1                                                                                                                          
/**
 * @fileoverview enforce a maximum file length
 * @author Alberto Rodríguez
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const lodash = require("lodash");
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce a maximum number of lines per file",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                oneOf: [
                    {
                        type: "integer",
                        minimum: 0
                    },
                    {
                        type: "object",
                        properties: {
                            max: {
                                type: "integer",
                                minimum: 0
                            },
                            skipComments: {
                                type: "boolean"
                            },
                            skipBlankLines: {
                                type: "boolean"
                            }
                        },
                        additionalProperties: false
                    }
                ]
            }
        ]
    },
 
    create(context) {
        const option = context.options[0];
        let max = 300;
 
        if (typeof option === "object" && option.hasOwnProperty("max") && typeof option.max === "number") {
            max = option.max;
        }
 
        if (typeof option === "number") {
            max = option;
        }
 
        const skipComments = option && option.skipComments;
        const skipBlankLines = option && option.skipBlankLines;
 
        const sourceCode = context.getSourceCode();
 
        /**
         * Returns whether or not a token is a comment node type
         * @param {Token} token The token to check
         * @returns {boolean} True if the token is a comment node
         */
        function isCommentNodeType(token) {
            return token && (token.type === "Block" || token.type === "Line");
        }
 
        /**
         * Returns the line numbers of a comment that don't have any code on the same line
         * @param {Node} comment The comment node to check
         * @returns {int[]} The line numbers
         */
        function getLinesWithoutCode(comment) {
            let start = comment.loc.start.line;
            let end = comment.loc.end.line;
 
            let token;
 
            token = comment;
            do {
                token = sourceCode.getTokenBefore(token, { includeComments: true });
            } while (isCommentNodeType(token));
 
            if (token && astUtils.isTokenOnSameLine(token, comment)) {
                start += 1;
            }
 
            token = comment;
            do {
                token = sourceCode.getTokenAfter(token, { includeComments: true });
            } while (isCommentNodeType(token));
 
            if (token && astUtils.isTokenOnSameLine(comment, token)) {
                end -= 1;
            }
 
            if (start <= end) {
                return lodash.range(start, end + 1);
            }
            return [];
        }
 
        return {
            "Program:exit"() {
                let lines = sourceCode.lines.map((text, i) => ({ lineNumber: i + 1, text }));
 
                if (skipBlankLines) {
                    lines = lines.filter(l => l.text.trim() !== "");
                }
 
                if (skipComments) {
                    const comments = sourceCode.getAllComments();
 
                    const commentLines = lodash.flatten(comments.map(comment => getLinesWithoutCode(comment)));
 
                    lines = lines.filter(l => !lodash.includes(commentLines, l.lineNumber));
                }
 
                if (lines.length > max) {
                    context.report({
                        loc: { line: 1, column: 0 },
                        message: "File must be at most {{max}} lines long. It's {{actual}} lines long.",
                        data: {
                            max,
                            actual: lines.length
                        }
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/max-nested-callbacks.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/max-nested-callbacks.js

Statements: 15% (3 / 20)      Branches: 0% (0 / 16)      Functions: 0% (0 / 3)      Lines: 15% (3 / 20)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114                      1                                                                                                                               1                                     1                                      
/**
 * @fileoverview Rule to enforce a maximum number of nested callbacks.
 * @author Ian Christian Myers
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce a maximum depth that callbacks can be nested",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                oneOf: [
                    {
                        type: "integer",
                        minimum: 0
                    },
                    {
                        type: "object",
                        properties: {
                            maximum: {
                                type: "integer",
                                minimum: 0
                            },
                            max: {
                                type: "integer",
                                minimum: 0
                            }
                        },
                        additionalProperties: false
                    }
                ]
            }
        ]
    },
 
    create(context) {
 
        //--------------------------------------------------------------------------
        // Constants
        //--------------------------------------------------------------------------
        const option = context.options[0];
        let THRESHOLD = 10;
 
        if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") {
            THRESHOLD = option.maximum;
        }
        if (typeof option === "object" && option.hasOwnProperty("max") && typeof option.max === "number") {
            THRESHOLD = option.max;
        }
        if (typeof option === "number") {
            THRESHOLD = option;
        }
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        const callbackStack = [];
 
        /**
         * Checks a given function node for too many callbacks.
         * @param {ASTNode} node The node to check.
         * @returns {void}
         * @private
         */
        function checkFunction(node) {
            const parent = node.parent;
 
            if (parent.type === "CallExpression") {
                callbackStack.push(node);
            }
 
            if (callbackStack.length > THRESHOLD) {
                const opts = { num: callbackStack.length, max: THRESHOLD };
 
                context.report({ node, message: "Too many nested callbacks ({{num}}). Maximum allowed is {{max}}.", data: opts });
            }
        }
 
        /**
         * Pops the call stack.
         * @returns {void}
         * @private
         */
        function popStack() {
            callbackStack.pop();
        }
 
        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------
 
        return {
            ArrowFunctionExpression: checkFunction,
            "ArrowFunctionExpression:exit": popStack,
 
            FunctionExpression: checkFunction,
            "FunctionExpression:exit": popStack
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/max-params.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/max-params.js

Statements: 26.67% (4 / 15)      Branches: 0% (0 / 14)      Functions: 0% (0 / 2)      Lines: 26.67% (4 / 15)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98                      1   1           1                                                                                                             1                                              
/**
 * @fileoverview Rule to flag when a function has too many parameters
 * @author Ilya Volodin
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const lodash = require("lodash");
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce a maximum number of parameters in function definitions",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                oneOf: [
                    {
                        type: "integer",
                        minimum: 0
                    },
                    {
                        type: "object",
                        properties: {
                            maximum: {
                                type: "integer",
                                minimum: 0
                            },
                            max: {
                                type: "integer",
                                minimum: 0
                            }
                        },
                        additionalProperties: false
                    }
                ]
            }
        ]
    },
 
    create(context) {
 
        const option = context.options[0];
        let numParams = 3;
 
        if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") {
            numParams = option.maximum;
        }
        if (typeof option === "object" && option.hasOwnProperty("max") && typeof option.max === "number") {
            numParams = option.max;
        }
        if (typeof option === "number") {
            numParams = option;
        }
 
        /**
         * Checks a function to see if it has too many parameters.
         * @param {ASTNode} node The node to check.
         * @returns {void}
         * @private
         */
        function checkFunction(node) {
            if (node.params.length > numParams) {
                context.report({
                    node,
                    message: "{{name}} has too many parameters ({{count}}). Maximum allowed is {{max}}.",
                    data: {
                        name: lodash.upperFirst(astUtils.getFunctionNameWithKind(node)),
                        count: node.params.length,
                        max: numParams
                    }
                });
            }
        }
 
        return {
            FunctionDeclaration: checkFunction,
            ArrowFunctionExpression: checkFunction,
            FunctionExpression: checkFunction
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/max-statements-per-line.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/max-statements-per-line.js

Statements: 20.69% (6 / 29)      Branches: 0% (0 / 20)      Functions: 0% (0 / 5)      Lines: 20.69% (6 / 29)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194                    1           1                                                                                       1                                         1                     1                                                                 1                                                                                                                                        
/**
 * @fileoverview Specify the maximum number of statements allowed per line.
 * @author Kenneth Williams
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce a maximum number of statements allowed per line",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    max: {
                        type: "integer",
                        minimum: 1
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        const sourceCode = context.getSourceCode(),
            options = context.options[0] || {},
            maxStatementsPerLine = typeof options.max !== "undefined" ? options.max : 1,
            message = "This line has {{numberOfStatementsOnThisLine}} {{statements}}. Maximum allowed is {{maxStatementsPerLine}}.";
 
        let lastStatementLine = 0,
            numberOfStatementsOnThisLine = 0,
            firstExtraStatement;
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        const SINGLE_CHILD_ALLOWED = /^(?:(?:DoWhile|For|ForIn|ForOf|If|Labeled|While)Statement|Export(?:Default|Named)Declaration)$/;
 
        /**
         * Reports with the first extra statement, and clears it.
         *
         * @returns {void}
         */
        function reportFirstExtraStatementAndClear() {
            if (firstExtraStatement) {
                context.report({
                    node: firstExtraStatement,
                    message,
                    data: {
                        numberOfStatementsOnThisLine,
                        maxStatementsPerLine,
                        statements: numberOfStatementsOnThisLine === 1 ? "statement" : "statements"
                    }
                });
            }
            firstExtraStatement = null;
        }
 
        /**
         * Gets the actual last token of a given node.
         *
         * @param {ASTNode} node - A node to get. This is a node except EmptyStatement.
         * @returns {Token} The actual last token.
         */
        function getActualLastToken(node) {
            return sourceCode.getLastToken(node, astUtils.isNotSemicolonToken);
        }
 
        /**
         * Addresses a given node.
         * It updates the state of this rule, then reports the node if the node violated this rule.
         *
         * @param {ASTNode} node - A node to check.
         * @returns {void}
         */
        function enterStatement(node) {
            const line = node.loc.start.line;
 
            // Skip to allow non-block statements if this is direct child of control statements.
            // `if (a) foo();` is counted as 1.
            // But `if (a) foo(); else foo();` should be counted as 2.
            if (SINGLE_CHILD_ALLOWED.test(node.parent.type) &&
                node.parent.alternate !== node
            ) {
                return;
            }
 
            // Update state.
            if (line === lastStatementLine) {
                numberOfStatementsOnThisLine += 1;
            } else {
                reportFirstExtraStatementAndClear();
                numberOfStatementsOnThisLine = 1;
                lastStatementLine = line;
            }
 
            // Reports if the node violated this rule.
            if (numberOfStatementsOnThisLine === maxStatementsPerLine + 1) {
                firstExtraStatement = firstExtraStatement || node;
            }
        }
 
        /**
         * Updates the state of this rule with the end line of leaving node to check with the next statement.
         *
         * @param {ASTNode} node - A node to check.
         * @returns {void}
         */
        function leaveStatement(node) {
            const line = getActualLastToken(node).loc.end.line;
 
            // Update state.
            if (line !== lastStatementLine) {
                reportFirstExtraStatementAndClear();
                numberOfStatementsOnThisLine = 1;
                lastStatementLine = line;
            }
        }
 
        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------
 
        return {
            BreakStatement: enterStatement,
            ClassDeclaration: enterStatement,
            ContinueStatement: enterStatement,
            DebuggerStatement: enterStatement,
            DoWhileStatement: enterStatement,
            ExpressionStatement: enterStatement,
            ForInStatement: enterStatement,
            ForOfStatement: enterStatement,
            ForStatement: enterStatement,
            FunctionDeclaration: enterStatement,
            IfStatement: enterStatement,
            ImportDeclaration: enterStatement,
            LabeledStatement: enterStatement,
            ReturnStatement: enterStatement,
            SwitchStatement: enterStatement,
            ThrowStatement: enterStatement,
            TryStatement: enterStatement,
            VariableDeclaration: enterStatement,
            WhileStatement: enterStatement,
            WithStatement: enterStatement,
            ExportNamedDeclaration: enterStatement,
            ExportDefaultDeclaration: enterStatement,
            ExportAllDeclaration: enterStatement,
 
            "BreakStatement:exit": leaveStatement,
            "ClassDeclaration:exit": leaveStatement,
            "ContinueStatement:exit": leaveStatement,
            "DebuggerStatement:exit": leaveStatement,
            "DoWhileStatement:exit": leaveStatement,
            "ExpressionStatement:exit": leaveStatement,
            "ForInStatement:exit": leaveStatement,
            "ForOfStatement:exit": leaveStatement,
            "ForStatement:exit": leaveStatement,
            "FunctionDeclaration:exit": leaveStatement,
            "IfStatement:exit": leaveStatement,
            "ImportDeclaration:exit": leaveStatement,
            "LabeledStatement:exit": leaveStatement,
            "ReturnStatement:exit": leaveStatement,
            "SwitchStatement:exit": leaveStatement,
            "ThrowStatement:exit": leaveStatement,
            "TryStatement:exit": leaveStatement,
            "VariableDeclaration:exit": leaveStatement,
            "WhileStatement:exit": leaveStatement,
            "WithStatement:exit": leaveStatement,
            "ExportNamedDeclaration:exit": leaveStatement,
            "ExportDefaultDeclaration:exit": leaveStatement,
            "ExportAllDeclaration:exit": leaveStatement,
            "Program:exit": reportFirstExtraStatementAndClear
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/max-statements.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/max-statements.js

Statements: 22.58% (7 / 31)      Branches: 0% (0 / 23)      Functions: 0% (0 / 6)      Lines: 22.58% (7 / 31)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172                      1   1           1                                                                                                                                                 1                                 1                   1                               1                                                                        
/**
 * @fileoverview A rule to set the maximum number of statements in a function.
 * @author Ian Christian Myers
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const lodash = require("lodash");
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce a maximum number of statements allowed in function blocks",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                oneOf: [
                    {
                        type: "integer",
                        minimum: 0
                    },
                    {
                        type: "object",
                        properties: {
                            maximum: {
                                type: "integer",
                                minimum: 0
                            },
                            max: {
                                type: "integer",
                                minimum: 0
                            }
                        },
                        additionalProperties: false
                    }
                ]
            },
            {
                type: "object",
                properties: {
                    ignoreTopLevelFunctions: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        const functionStack = [],
            option = context.options[0],
            ignoreTopLevelFunctions = context.options[1] && context.options[1].ignoreTopLevelFunctions || false,
            topLevelFunctions = [];
        let maxStatements = 10;
 
        if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") {
            maxStatements = option.maximum;
        }
        if (typeof option === "object" && option.hasOwnProperty("max") && typeof option.max === "number") {
            maxStatements = option.max;
        }
        if (typeof option === "number") {
            maxStatements = option;
        }
 
        /**
         * Reports a node if it has too many statements
         * @param {ASTNode} node node to evaluate
         * @param {int} count Number of statements in node
         * @param {int} max Maximum number of statements allowed
         * @returns {void}
         * @private
         */
        function reportIfTooManyStatements(node, count, max) {
            if (count > max) {
                const name = lodash.upperFirst(astUtils.getFunctionNameWithKind(node));
 
                context.report({
                    node,
                    message: "{{name}} has too many statements ({{count}}). Maximum allowed is {{max}}.",
                    data: { name, count, max }
                });
            }
        }
 
        /**
         * When parsing a new function, store it in our function stack
         * @returns {void}
         * @private
         */
        function startFunction() {
            functionStack.push(0);
        }
 
        /**
         * Evaluate the node at the end of function
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function endFunction(node) {
            const count = functionStack.pop();
 
            if (ignoreTopLevelFunctions && functionStack.length === 0) {
                topLevelFunctions.push({ node, count });
            } else {
                reportIfTooManyStatements(node, count, maxStatements);
            }
        }
 
        /**
         * Increment the count of the functions
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function countStatements(node) {
            functionStack[functionStack.length - 1] += node.body.length;
        }
 
        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------
 
        return {
            FunctionDeclaration: startFunction,
            FunctionExpression: startFunction,
            ArrowFunctionExpression: startFunction,
 
            BlockStatement: countStatements,
 
            "FunctionDeclaration:exit": endFunction,
            "FunctionExpression:exit": endFunction,
            "ArrowFunctionExpression:exit": endFunction,
 
            "Program:exit"() {
                if (topLevelFunctions.length === 1) {
                    return;
                }
 
                topLevelFunctions.forEach(element => {
                    const count = element.count;
                    const node = element.node;
 
                    reportIfTooManyStatements(node, count, maxStatements);
                });
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/multiline-ternary.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/multiline-ternary.js

Statements: 17.65% (3 / 17)      Branches: 0% (0 / 14)      Functions: 0% (0 / 3)      Lines: 17.65% (3 / 17)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85              1           1                                                         1                                                                                    
/**
 * @fileoverview Enforce newlines between operands of ternary expressions
 * @author Kai Cataldo
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce newlines between operands of ternary expressions",
            category: "Stylistic Issues",
            recommended: false
        },
        schema: [
            {
                enum: ["always", "never"]
            }
        ]
    },
 
    create(context) {
        const multiline = context.options[0] !== "never";
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Tests whether node is preceded by supplied tokens
         * @param {ASTNode} node - node to check
         * @param {ASTNode} parentNode - parent of node to report
         * @param {boolean} expected - whether newline was expected or not
         * @returns {void}
         * @private
         */
        function reportError(node, parentNode, expected) {
            context.report({
                node,
                message: "{{expected}} newline between {{typeOfError}} of ternary expression.",
                data: {
                    expected: expected ? "Expected" : "Unexpected",
                    typeOfError: node === parentNode.test ? "test and consequent" : "consequent and alternate"
                }
            });
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            ConditionalExpression(node) {
                const areTestAndConsequentOnSameLine = astUtils.isTokenOnSameLine(node.test, node.consequent);
                const areConsequentAndAlternateOnSameLine = astUtils.isTokenOnSameLine(node.consequent, node.alternate);
 
                if (!multiline) {
                    if (!areTestAndConsequentOnSameLine) {
                        reportError(node.test, node, false);
                    }
 
                    if (!areConsequentAndAlternateOnSameLine) {
                        reportError(node.consequent, node, false);
                    }
                } else {
                    if (areTestAndConsequentOnSameLine) {
                        reportError(node.test, node, true);
                    }
 
                    if (areConsequentAndAlternateOnSameLine) {
                        reportError(node.consequent, node, true);
                    }
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/new-cap.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/new-cap.js

Statements: 13.51% (10 / 74)      Branches: 1.61% (1 / 62)      Functions: 0% (0 / 10)      Lines: 13.51% (10 / 74)      Ignored: 1 statement, 1 branch     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273                              1                                       1       1                     1                   1                           1                                                                                                                                               1                                               1                                                 1                                                     1                                                                                                    
/**
 * @fileoverview Rule to flag use of constructors without capital letters
 * @author Nicholas C. Zakas
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const CAPS_ALLOWED = [
    "Array",
    "Boolean",
    "Date",
    "Error",
    "Function",
    "Number",
    "Object",
    "RegExp",
    "String",
    "Symbol"
];
 
/**
 * Ensure that if the key is provided, it must be an array.
 * @param {Object} obj Object to check with `key`.
 * @param {string} key Object key to check on `obj`.
 * @param {*} fallback If obj[key] is not present, this will be returned.
 * @returns {string[]} Returns obj[key] if it's an Array, otherwise `fallback`
 */
function checkArray(obj, key, fallback) {
 
    /* istanbul ignore if */
    if (Object.prototype.hasOwnProperty.call(obj, key) && !Array.isArray(obj[key])) {
        throw new TypeError(`${key}, if provided, must be an Array`);
    }
    return obj[key] || fallback;
}
 
/**
 * A reducer function to invert an array to an Object mapping the string form of the key, to `true`.
 * @param {Object} map Accumulator object for the reduce.
 * @param {string} key Object key to set to `true`.
 * @returns {Object} Returns the updated Object for further reduction.
 */
function invert(map, key) {
    map[key] = true;
    return map;
}
 
/**
 * Creates an object with the cap is new exceptions as its keys and true as their values.
 * @param {Object} config Rule configuration
 * @returns {Object} Object with cap is new exceptions.
 */
function calculateCapIsNewExceptions(config) {
    let capIsNewExceptions = checkArray(config, "capIsNewExceptions", CAPS_ALLOWED);
 
    if (capIsNewExceptions !== CAPS_ALLOWED) {
        capIsNewExceptions = capIsNewExceptions.concat(CAPS_ALLOWED);
    }
 
    return capIsNewExceptions.reduce(invert, {});
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require constructor names to begin with a capital letter",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    newIsCap: {
                        type: "boolean"
                    },
                    capIsNew: {
                        type: "boolean"
                    },
                    newIsCapExceptions: {
                        type: "array",
                        items: {
                            type: "string"
                        }
                    },
                    newIsCapExceptionPattern: {
                        type: "string"
                    },
                    capIsNewExceptions: {
                        type: "array",
                        items: {
                            type: "string"
                        }
                    },
                    capIsNewExceptionPattern: {
                        type: "string"
                    },
                    properties: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        const config = context.options[0] ? Object.assign({}, context.options[0]) : {};
 
        config.newIsCap = config.newIsCap !== false;
        config.capIsNew = config.capIsNew !== false;
        const skipProperties = config.properties === false;
 
        const newIsCapExceptions = checkArray(config, "newIsCapExceptions", []).reduce(invert, {});
        const newIsCapExceptionPattern = config.newIsCapExceptionPattern ? new RegExp(config.newIsCapExceptionPattern) : null;
 
        const capIsNewExceptions = calculateCapIsNewExceptions(config);
        const capIsNewExceptionPattern = config.capIsNewExceptionPattern ? new RegExp(config.capIsNewExceptionPattern) : null;
 
        const listeners = {};
 
        const sourceCode = context.getSourceCode();
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Get exact callee name from expression
         * @param {ASTNode} node CallExpression or NewExpression node
         * @returns {string} name
         */
        function extractNameFromExpression(node) {
 
            let name = "";
 
            if (node.callee.type === "MemberExpression") {
                const property = node.callee.property;
 
                if (property.type === "Literal" && (typeof property.value === "string")) {
                    name = property.value;
                } else if (property.type === "Identifier" && !node.callee.computed) {
                    name = property.name;
                }
            } else {
                name = node.callee.name;
            }
            return name;
        }
 
        /**
         * Returns the capitalization state of the string -
         * Whether the first character is uppercase, lowercase, or non-alphabetic
         * @param {string} str String
         * @returns {string} capitalization state: "non-alpha", "lower", or "upper"
         */
        function getCap(str) {
            const firstChar = str.charAt(0);
 
            const firstCharLower = firstChar.toLowerCase();
            const firstCharUpper = firstChar.toUpperCase();
 
            if (firstCharLower === firstCharUpper) {
 
                // char has no uppercase variant, so it's non-alphabetic
                return "non-alpha";
            } else if (firstChar === firstCharLower) {
                return "lower";
            }
            return "upper";
 
        }
 
        /**
         * Check if capitalization is allowed for a CallExpression
         * @param {Object} allowedMap Object mapping calleeName to a Boolean
         * @param {ASTNode} node CallExpression node
         * @param {string} calleeName Capitalized callee name from a CallExpression
         * @param {Object} pattern RegExp object from options pattern
         * @returns {boolean} Returns true if the callee may be capitalized
         */
        function isCapAllowed(allowedMap, node, calleeName, pattern) {
            const sourceText = sourceCode.getText(node.callee);
 
            if (allowedMap[calleeName] || allowedMap[sourceText]) {
                return true;
            }
 
            if (pattern && pattern.test(sourceText)) {
                return true;
            }
 
            if (calleeName === "UTC" && node.callee.type === "MemberExpression") {
 
                // allow if callee is Date.UTC
                return node.callee.object.type === "Identifier" &&
                    node.callee.object.name === "Date";
            }
 
            return skipProperties && node.callee.type === "MemberExpression";
        }
 
        /**
         * Reports the given message for the given node. The location will be the start of the property or the callee.
         * @param {ASTNode} node CallExpression or NewExpression node.
         * @param {string} message The message to report.
         * @returns {void}
         */
        function report(node, message) {
            let callee = node.callee;
 
            if (callee.type === "MemberExpression") {
                callee = callee.property;
            }
 
            context.report({ node, loc: callee.loc.start, message });
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        if (config.newIsCap) {
            listeners.NewExpression = function(node) {
 
                const constructorName = extractNameFromExpression(node);
 
                if (constructorName) {
                    const capitalization = getCap(constructorName);
                    const isAllowed = capitalization !== "lower" || isCapAllowed(newIsCapExceptions, node, constructorName, newIsCapExceptionPattern);
 
                    if (!isAllowed) {
                        report(node, "A constructor name should not start with a lowercase letter.");
                    }
                }
            };
        }
 
        if (config.capIsNew) {
            listeners.CallExpression = function(node) {
 
                const calleeName = extractNameFromExpression(node);
 
                if (calleeName) {
                    const capitalization = getCap(calleeName);
                    const isAllowed = capitalization !== "upper" || isCapAllowed(capIsNewExceptions, node, calleeName, capIsNewExceptionPattern);
 
                    if (!isAllowed) {
                        report(node, "A function with a name starting with an uppercase letter should only be used as a constructor.");
                    }
                }
            };
        }
 
        return listeners;
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/new-parens.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/new-parens.js

Statements: 16.67% (2 / 12)      Branches: 0% (0 / 8)      Functions: 0% (0 / 2)      Lines: 16.67% (2 / 12)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60                      1                   1                                                                            
/**
 * @fileoverview Rule to flag when using constructor without parentheses
 * @author Ilya Volodin
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require parentheses when invoking a constructor with no arguments",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [],
 
        fixable: "code"
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        return {
            NewExpression(node) {
                if (node.arguments.length !== 0) {
                    return;  // shortcut: if there are arguments, there have to be parens
                }
 
                const lastToken = sourceCode.getLastToken(node);
                const hasLastParen = lastToken && astUtils.isClosingParenToken(lastToken);
                const hasParens = hasLastParen && astUtils.isOpeningParenToken(sourceCode.getTokenBefore(lastToken));
 
                if (!hasParens) {
                    context.report({
                        node,
                        message: "Missing '()' invoking a constructor.",
                        fix: fixer => fixer.insertTextAfter(node, "()")
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/newline-after-var.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/newline-after-var.js

Statements: 18.87% (10 / 53)      Branches: 0% (0 / 52)      Functions: 0% (0 / 11)      Lines: 18.87% (10 / 53)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250                      1           1                                                                                                             1                                       1                   1                   1                     1                     1                       1                       1                                                                                                                                                                                      
/**
 * @fileoverview Rule to check empty newline after "var" statement
 * @author Gopal Venkatesan
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require or disallow an empty line after variable declarations",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                enum: ["never", "always"]
            }
        ],
 
        fixable: "whitespace"
    },
 
    create(context) {
 
        const ALWAYS_MESSAGE = "Expected blank line after variable declarations.",
            NEVER_MESSAGE = "Unexpected blank line after variable declarations.";
 
        const sourceCode = context.getSourceCode();
 
        // Default `mode` to "always".
        const mode = context.options[0] === "never" ? "never" : "always";
 
        // Cache starting and ending line numbers of comments for faster lookup
        const commentEndLine = sourceCode.getAllComments().reduce((result, token) => {
            result[token.loc.start.line] = token.loc.end.line;
            return result;
        }, {});
 
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Gets a token from the given node to compare line to the next statement.
         *
         * In general, the token is the last token of the node. However, the token is the second last token if the following conditions satisfy.
         *
         * - The last token is semicolon.
         * - The semicolon is on a different line from the previous token of the semicolon.
         *
         * This behavior would address semicolon-less style code. e.g.:
         *
         *     var foo = 1
         *
         *     ;(a || b).doSomething()
         *
         * @param {ASTNode} node - The node to get.
         * @returns {Token} The token to compare line to the next statement.
         */
        function getLastToken(node) {
            const lastToken = sourceCode.getLastToken(node);
 
            if (lastToken.type === "Punctuator" && lastToken.value === ";") {
                const prevToken = sourceCode.getTokenBefore(lastToken);
 
                if (prevToken.loc.end.line !== lastToken.loc.start.line) {
                    return prevToken;
                }
            }
 
            return lastToken;
        }
 
        /**
         * Determine if provided keyword is a variable declaration
         * @private
         * @param {string} keyword - keyword to test
         * @returns {boolean} True if `keyword` is a type of var
         */
        function isVar(keyword) {
            return keyword === "var" || keyword === "let" || keyword === "const";
        }
 
        /**
         * Determine if provided keyword is a variant of for specifiers
         * @private
         * @param {string} keyword - keyword to test
         * @returns {boolean} True if `keyword` is a variant of for specifier
         */
        function isForTypeSpecifier(keyword) {
            return keyword === "ForStatement" || keyword === "ForInStatement" || keyword === "ForOfStatement";
        }
 
        /**
         * Determine if provided keyword is an export specifiers
         * @private
         * @param {string} nodeType - nodeType to test
         * @returns {boolean} True if `nodeType` is an export specifier
         */
        function isExportSpecifier(nodeType) {
            return nodeType === "ExportNamedDeclaration" || nodeType === "ExportSpecifier" ||
                nodeType === "ExportDefaultDeclaration" || nodeType === "ExportAllDeclaration";
        }
 
        /**
         * Determine if provided node is the last of their parent block.
         * @private
         * @param {ASTNode} node - node to test
         * @returns {boolean} True if `node` is last of their parent block.
         */
        function isLastNode(node) {
            const token = sourceCode.getTokenAfter(node);
 
            return !token || (token.type === "Punctuator" && token.value === "}");
        }
 
        /**
        * Gets the last line of a group of consecutive comments
        * @param {number} commentStartLine The starting line of the group
        * @returns {number} The number of the last comment line of the group
        */
        function getLastCommentLineOfBlock(commentStartLine) {
            const currentCommentEnd = commentEndLine[commentStartLine];
 
            return commentEndLine[currentCommentEnd + 1] ? getLastCommentLineOfBlock(currentCommentEnd + 1) : currentCommentEnd;
        }
 
        /**
         * Determine if a token starts more than one line after a comment ends
         * @param  {token}   token            The token being checked
         * @param {integer}  commentStartLine The line number on which the comment starts
         * @returns {boolean}                 True if `token` does not start immediately after a comment
         */
        function hasBlankLineAfterComment(token, commentStartLine) {
            return token.loc.start.line > getLastCommentLineOfBlock(commentStartLine) + 1;
        }
 
        /**
         * Checks that a blank line exists after a variable declaration when mode is
         * set to "always", or checks that there is no blank line when mode is set
         * to "never"
         * @private
         * @param {ASTNode} node - `VariableDeclaration` node to test
         * @returns {void}
         */
        function checkForBlankLine(node) {
 
            /*
             * lastToken is the last token on the node's line. It will usually also be the last token of the node, but it will
             * sometimes be second-last if there is a semicolon on a different line.
             */
            const lastToken = getLastToken(node),
 
                /*
                 * If lastToken is the last token of the node, nextToken should be the token after the node. Otherwise, nextToken
                 * is the last token of the node.
                 */
                nextToken = lastToken === sourceCode.getLastToken(node) ? sourceCode.getTokenAfter(node) : sourceCode.getLastToken(node),
                nextLineNum = lastToken.loc.end.line + 1;
 
            // Ignore if there is no following statement
            if (!nextToken) {
                return;
            }
 
            // Ignore if parent of node is a for variant
            if (isForTypeSpecifier(node.parent.type)) {
                return;
            }
 
            // Ignore if parent of node is an export specifier
            if (isExportSpecifier(node.parent.type)) {
                return;
            }
 
            // Some coding styles use multiple `var` statements, so do nothing if
            // the next token is a `var` statement.
            if (nextToken.type === "Keyword" && isVar(nextToken.value)) {
                return;
            }
 
            // Ignore if it is last statement in a block
            if (isLastNode(node)) {
                return;
            }
 
            // Next statement is not a `var`...
            const noNextLineToken = nextToken.loc.start.line > nextLineNum;
            const hasNextLineComment = (typeof commentEndLine[nextLineNum] !== "undefined");
 
            if (mode === "never" && noNextLineToken && !hasNextLineComment) {
                context.report({
                    node,
                    message: NEVER_MESSAGE,
                    data: { identifier: node.name },
                    fix(fixer) {
                        const linesBetween = sourceCode.getText().slice(lastToken.range[1], nextToken.range[0]).split(astUtils.LINEBREAK_MATCHER);
 
                        return fixer.replaceTextRange([lastToken.range[1], nextToken.range[0]], `${linesBetween.slice(0, -1).join("")}\n${linesBetween[linesBetween.length - 1]}`);
                    }
                });
            }
 
            // Token on the next line, or comment without blank line
            if (
                mode === "always" && (
                    !noNextLineToken ||
                    hasNextLineComment && !hasBlankLineAfterComment(nextToken, nextLineNum)
                )
            ) {
                context.report({
                    node,
                    message: ALWAYS_MESSAGE,
                    data: { identifier: node.name },
                    fix(fixer) {
                        if ((noNextLineToken ? getLastCommentLineOfBlock(nextLineNum) : lastToken.loc.end.line) === nextToken.loc.start.line) {
                            return fixer.insertTextBefore(nextToken, "\n\n");
                        }
 
                        return fixer.insertTextBeforeRange([nextToken.range[0] - nextToken.loc.start.column, nextToken.range[1]], "\n");
                    }
                });
            }
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            VariableDeclaration: checkForBlankLine
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/newline-before-return.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/newline-before-return.js

Statements: 11.67% (7 / 60)      Branches: 0% (0 / 34)      Functions: 0% (0 / 9)      Lines: 11.86% (7 / 59)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205                    1                                                 1                       1                                                     1                                                                   1                                                     1                                     1                                                                                                    
/**
 * @fileoverview Rule to require newlines before `return` statement
 * @author Kai Cataldo
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require an empty line before `return` statements",
            category: "Stylistic Issues",
            recommended: false
        },
        fixable: "whitespace",
        schema: []
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Tests whether node is preceded by supplied tokens
         * @param {ASTNode} node - node to check
         * @param {array} testTokens - array of tokens to test against
         * @returns {boolean} Whether or not the node is preceded by one of the supplied tokens
         * @private
         */
        function isPrecededByTokens(node, testTokens) {
            const tokenBefore = sourceCode.getTokenBefore(node);
 
            return testTokens.some(token => tokenBefore.value === token);
        }
 
        /**
         * Checks whether node is the first node after statement or in block
         * @param {ASTNode} node - node to check
         * @returns {boolean} Whether or not the node is the first node after statement or in block
         * @private
         */
        function isFirstNode(node) {
            const parentType = node.parent.type;
 
            if (node.parent.body) {
                return Array.isArray(node.parent.body)
                  ? node.parent.body[0] === node
                  : node.parent.body === node;
            }
 
            if (parentType === "IfStatement") {
                return isPrecededByTokens(node, ["else", ")"]);
            } else if (parentType === "DoWhileStatement") {
                return isPrecededByTokens(node, ["do"]);
            } else if (parentType === "SwitchCase") {
                return isPrecededByTokens(node, [":"]);
            }
            return isPrecededByTokens(node, [")"]);
 
        }
 
        /**
         * Returns the number of lines of comments that precede the node
         * @param {ASTNode} node - node to check for overlapping comments
         * @param {number} lineNumTokenBefore - line number of previous token, to check for overlapping comments
         * @returns {number} Number of lines of comments that precede the node
         * @private
         */
        function calcCommentLines(node, lineNumTokenBefore) {
            const comments = sourceCode.getComments(node).leading;
            let numLinesComments = 0;
 
            if (!comments.length) {
                return numLinesComments;
            }
 
            comments.forEach(comment => {
                numLinesComments++;
 
                if (comment.type === "Block") {
                    numLinesComments += comment.loc.end.line - comment.loc.start.line;
                }
 
                // avoid counting lines with inline comments twice
                if (comment.loc.start.line === lineNumTokenBefore) {
                    numLinesComments--;
                }
 
                if (comment.loc.end.line === node.loc.start.line) {
                    numLinesComments--;
                }
            });
 
            return numLinesComments;
        }
 
        /**
         * Returns the line number of the token before the node that is passed in as an argument
         * @param {ASTNode} node - The node to use as the start of the calculation
         * @returns {number} Line number of the token before `node`
         * @private
         */
        function getLineNumberOfTokenBefore(node) {
            const tokenBefore = sourceCode.getTokenBefore(node);
            let lineNumTokenBefore;
 
            /**
             * Global return (at the beginning of a script) is a special case.
             * If there is no token before `return`, then we expect no line
             * break before the return. Comments are allowed to occupy lines
             * before the global return, just no blank lines.
             * Setting lineNumTokenBefore to zero in that case results in the
             * desired behavior.
             */
            if (tokenBefore) {
                lineNumTokenBefore = tokenBefore.loc.end.line;
            } else {
                lineNumTokenBefore = 0;     // global return at beginning of script
            }
 
            return lineNumTokenBefore;
        }
 
        /**
         * Checks whether node is preceded by a newline
         * @param {ASTNode} node - node to check
         * @returns {boolean} Whether or not the node is preceded by a newline
         * @private
         */
        function hasNewlineBefore(node) {
            const lineNumNode = node.loc.start.line;
            const lineNumTokenBefore = getLineNumberOfTokenBefore(node);
            const commentLines = calcCommentLines(node, lineNumTokenBefore);
 
            return (lineNumNode - lineNumTokenBefore - commentLines) > 1;
        }
 
        /**
         * Checks whether it is safe to apply a fix to a given return statement.
         *
         * The fix is not considered safe if the given return statement has leading comments,
         * as we cannot safely determine if the newline should be added before or after the comments.
         * For more information, see: https://github.com/eslint/eslint/issues/5958#issuecomment-222767211
         *
         * @param {ASTNode} node - The return statement node to check.
         * @returns {boolean} `true` if it can fix the node.
         * @private
         */
        function canFix(node) {
            const leadingComments = sourceCode.getComments(node).leading;
            const lastLeadingComment = leadingComments[leadingComments.length - 1];
            const tokenBefore = sourceCode.getTokenBefore(node);
 
            if (leadingComments.length === 0) {
                return true;
            }
 
            // if the last leading comment ends in the same line as the previous token and
            // does not share a line with the `return` node, we can consider it safe to fix.
            // Example:
            // function a() {
            //     var b; //comment
            //     return;
            // }
            if (lastLeadingComment.loc.end.line === tokenBefore.loc.end.line &&
                lastLeadingComment.loc.end.line !== node.loc.start.line) {
                return true;
            }
 
            return false;
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            ReturnStatement(node) {
                if (!isFirstNode(node) && !hasNewlineBefore(node)) {
                    context.report({
                        node,
                        message: "Expected newline before return statement.",
                        fix(fixer) {
                            if (canFix(node)) {
                                const tokenBefore = sourceCode.getTokenBefore(node);
                                const newlines = node.loc.start.line === tokenBefore.loc.end.line ? "\n\n" : "\n";
 
                                return fixer.insertTextBefore(node, newlines);
                            }
                            return null;
                        }
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/newline-per-chained-call.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/newline-per-chained-call.js

Statements: 15% (3 / 20)      Branches: 0% (0 / 20)      Functions: 0% (0 / 3)      Lines: 15% (3 / 20)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88                1           1                                                                     1                                                                            
/**
 * @fileoverview Rule to ensure newline per method call when chaining calls
 * @author Rajendra Patil
 * @author Burak Yigit Kaya
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require a newline after each call in a method chain",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [{
            type: "object",
            properties: {
                ignoreChainWithDepth: {
                    type: "integer",
                    minimum: 1,
                    maximum: 10
                }
            },
            additionalProperties: false
        }]
    },
 
    create(context) {
 
        const options = context.options[0] || {},
            ignoreChainWithDepth = options.ignoreChainWithDepth || 2;
 
        const sourceCode = context.getSourceCode();
 
        /**
         * Gets the property text of a given MemberExpression node.
         * If the text is multiline, this returns only the first line.
         *
         * @param {ASTNode} node - A MemberExpression node to get.
         * @returns {string} The property text of the node.
         */
        function getPropertyText(node) {
            const prefix = node.computed ? "[" : ".";
            const lines = sourceCode.getText(node.property).split(astUtils.LINEBREAK_MATCHER);
            const suffix = node.computed && lines.length === 1 ? "]" : "";
 
            return prefix + lines[0] + suffix;
        }
 
        return {
            "CallExpression:exit"(node) {
                if (!node.callee || node.callee.type !== "MemberExpression") {
                    return;
                }
 
                const callee = node.callee;
                let parent = callee.object;
                let depth = 1;
 
                while (parent && parent.callee) {
                    depth += 1;
                    parent = parent.callee.object;
                }
 
                if (depth > ignoreChainWithDepth && callee.property.loc.start.line === callee.object.loc.end.line) {
                    context.report({
                        node: callee.property,
                        loc: callee.property.loc.start,
                        message: "Expected line break before `{{callee}}`.",
                        data: {
                            callee: getPropertyText(callee)
                        }
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-alert.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-alert.js

Statements: 21.21% (7 / 33)      Branches: 0% (0 / 25)      Functions: 0% (0 / 8)      Lines: 21.88% (7 / 32)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133                    1                     1                     1                   1                                 1                         1                           1                                                                                            
/**
 * @fileoverview Rule to flag use of alert, confirm, prompt
 * @author Nicholas C. Zakas
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const getPropertyName = require("../ast-utils").getStaticPropertyName;
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks if the given name is a prohibited identifier.
 * @param {string} name The name to check
 * @returns {boolean} Whether or not the name is prohibited.
 */
function isProhibitedIdentifier(name) {
    return /^(alert|confirm|prompt)$/.test(name);
}
 
/**
 * Reports the given node and identifier name.
 * @param {RuleContext} context The ESLint rule context.
 * @param {ASTNode} node The node to report on.
 * @param {string} identifierName The name of the identifier.
 * @returns {void}
 */
function report(context, node, identifierName) {
    context.report(node, "Unexpected {{name}}.", { name: identifierName });
}
 
/**
 * Finds the escope reference in the given scope.
 * @param {Object} scope The scope to search.
 * @param {ASTNode} node The identifier node.
 * @returns {Reference|null} Returns the found reference or null if none were found.
 */
function findReference(scope, node) {
    const references = scope.references.filter(reference => reference.identifier.range[0] === node.range[0] &&
            reference.identifier.range[1] === node.range[1]);
 
    if (references.length === 1) {
        return references[0];
    }
    return null;
}
 
/**
 * Checks if the given identifier node is shadowed in the given scope.
 * @param {Object} scope The current scope.
 * @param {Object} globalScope The global scope.
 * @param {string} node The identifier node to check
 * @returns {boolean} Whether or not the name is shadowed.
 */
function isShadowed(scope, globalScope, node) {
    const reference = findReference(scope, node);
 
    return reference && reference.resolved && reference.resolved.defs.length > 0;
}
 
/**
 * Checks if the given identifier node is a ThisExpression in the global scope or the global window property.
 * @param {Object} scope The current scope.
 * @param {Object} globalScope The global scope.
 * @param {string} node The identifier node to check
 * @returns {boolean} Whether or not the node is a reference to the global object.
 */
function isGlobalThisReferenceOrGlobalWindow(scope, globalScope, node) {
    if (scope.type === "global" && node.type === "ThisExpression") {
        return true;
    } else if (node.name === "window") {
        return !isShadowed(scope, globalScope, node);
    }
 
    return false;
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow the use of `alert`, `confirm`, and `prompt`",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
        let globalScope;
 
        return {
 
            Program() {
                globalScope = context.getScope();
            },
 
            CallExpression(node) {
                const callee = node.callee,
                    currentScope = context.getScope();
 
                // without window.
                if (callee.type === "Identifier") {
                    const identifierName = callee.name;
 
                    if (!isShadowed(currentScope, globalScope, callee) && isProhibitedIdentifier(callee.name)) {
                        report(context, node, identifierName);
                    }
 
                } else if (callee.type === "MemberExpression" && isGlobalThisReferenceOrGlobalWindow(currentScope, globalScope, callee.object)) {
                    const identifierName = getPropertyName(callee);
 
                    if (isProhibitedIdentifier(identifierName)) {
                        report(context, node, identifierName);
                    }
                }
 
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-array-constructor.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-array-constructor.js

Statements: 40% (2 / 5)      Branches: 0% (0 / 5)      Functions: 0% (0 / 2)      Lines: 40% (2 / 5)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49                      1                                     1                                    
/**
 * @fileoverview Disallow construction of dense arrays using the Array constructor
 * @author Matt DuVall <http://www.mattduvall.com/>
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `Array` constructors",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        /**
         * Disallow construction of dense arrays using the Array constructor
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function check(node) {
            if (
                node.arguments.length !== 1 &&
                node.callee.type === "Identifier" &&
                node.callee.name === "Array"
            ) {
                context.report({ node, message: "The array literal notation [] is preferrable." });
            }
        }
 
        return {
            CallExpression: check,
            NewExpression: check
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-await-in-loop.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-await-in-loop.js

Statements: 20% (3 / 15)      Branches: 0% (0 / 9)      Functions: 0% (0 / 2)      Lines: 20% (3 / 15)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77              1                   1           1                                                                                                          
/**
 * @fileoverview Rule to disallow uses of await inside of loops.
 * @author Nat Mote (nmote)
 */
"use strict";
 
// Node types which are considered loops.
const loopTypes = new Set([
    "ForStatement",
    "ForOfStatement",
    "ForInStatement",
    "WhileStatement",
    "DoWhileStatement"
]);
 
// Node types at which we should stop looking for loops. For example, it is fine to declare an async
// function within a loop, and use await inside of that.
const boundaryTypes = new Set([
    "FunctionDeclaration",
    "FunctionExpression",
    "ArrowFunctionExpression"
]);
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `await` inside of loops",
            category: "Possible Errors",
            recommended: false
        },
        schema: []
    },
    create(context) {
        return {
            AwaitExpression(node) {
                const ancestors = context.getAncestors();
 
                // Reverse so that we can traverse from the deepest node upwards.
                ancestors.reverse();
 
                // Create a set of all the ancestors plus this node so that we can check
                // if this use of await appears in the body of the loop as opposed to
                // the right-hand side of a for...of, for example.
                const ancestorSet = new Set(ancestors).add(node);
 
                for (let i = 0; i < ancestors.length; i++) {
                    const ancestor = ancestors[i];
 
                    if (boundaryTypes.has(ancestor.type)) {
 
                        // Short-circuit out if we encounter a boundary type. Loops above
                        // this do not matter.
                        return;
                    }
                    if (loopTypes.has(ancestor.type)) {
 
                        // Only report if we are actually in the body or another part that gets executed on
                        // every iteration.
                        if (
                            ancestorSet.has(ancestor.body) ||
                            ancestorSet.has(ancestor.test) ||
                            ancestorSet.has(ancestor.update)
                        ) {
                            context.report({
                                node,
                                message: "Unexpected `await` inside a loop."
                            });
                            return;
                        }
                    }
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-bitwise.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-bitwise.js

Statements: 41.18% (7 / 17)      Branches: 0% (0 / 14)      Functions: 0% (0 / 6)      Lines: 41.18% (7 / 17)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111                    1                   1                                                                           1                 1                 1                 1                   1                              
/**
 * @fileoverview Rule to flag bitwise identifiers
 * @author Nicholas C. Zakas
 */
 
"use strict";
 
//
// Set of bitwise operators.
//
const BITWISE_OPERATORS = [
    "^", "|", "&", "<<", ">>", ">>>",
    "^=", "|=", "&=", "<<=", ">>=", ">>>=",
    "~"
];
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow bitwise operators",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    allow: {
                        type: "array",
                        items: {
                            enum: BITWISE_OPERATORS
                        },
                        uniqueItems: true
                    },
                    int32Hint: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const options = context.options[0] || {};
        const allowed = options.allow || [];
        const int32Hint = options.int32Hint === true;
 
        /**
         * Reports an unexpected use of a bitwise operator.
         * @param   {ASTNode} node Node which contains the bitwise operator.
         * @returns {void}
         */
        function report(node) {
            context.report({ node, message: "Unexpected use of '{{operator}}'.", data: { operator: node.operator } });
        }
 
        /**
         * Checks if the given node has a bitwise operator.
         * @param   {ASTNode} node The node to check.
         * @returns {boolean} Whether or not the node has a bitwise operator.
         */
        function hasBitwiseOperator(node) {
            return BITWISE_OPERATORS.indexOf(node.operator) !== -1;
        }
 
        /**
         * Checks if exceptions were provided, e.g. `{ allow: ['~', '|'] }`.
         * @param   {ASTNode} node The node to check.
         * @returns {boolean} Whether or not the node has a bitwise operator.
         */
        function allowedOperator(node) {
            return allowed.indexOf(node.operator) !== -1;
        }
 
        /**
         * Checks if the given bitwise operator is used for integer typecasting, i.e. "|0"
         * @param   {ASTNode} node The node to check.
         * @returns {boolean} whether the node is used in integer typecasting.
         */
        function isInt32Hint(node) {
            return int32Hint && node.operator === "|" && node.right &&
              node.right.type === "Literal" && node.right.value === 0;
        }
 
        /**
         * Report if the given node contains a bitwise operator.
         * @param   {ASTNode} node The node to check.
         * @returns {void}
         */
        function checkNodeForBitwiseOperator(node) {
            if (hasBitwiseOperator(node) && !allowedOperator(node) && !isInt32Hint(node)) {
                report(node);
            }
        }
 
        return {
            AssignmentExpression: checkNodeForBitwiseOperator,
            BinaryExpression: checkNodeForBitwiseOperator,
            UnaryExpression: checkNodeForBitwiseOperator
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-caller.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-caller.js

Statements: 20% (1 / 5)      Branches: 0% (0 / 6)      Functions: 0% (0 / 2)      Lines: 20% (1 / 5)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41                      1                                                          
/**
 * @fileoverview Rule to flag use of arguments.callee and arguments.caller.
 * @author Nicholas C. Zakas
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow the use of `arguments.caller` or `arguments.callee`",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
 
            MemberExpression(node) {
                const objectName = node.object.name,
                    propertyName = node.property.name;
 
                if (objectName === "arguments" && !node.computed && propertyName && propertyName.match(/^calle[er]$/)) {
                    context.report({ node, message: "Avoid arguments.{{property}}.", data: { property: propertyName } });
                }
 
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-case-declarations.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-case-declarations.js

Statements: 18.18% (2 / 11)      Branches: 0% (0 / 6)      Functions: 0% (0 / 3)      Lines: 18.18% (2 / 11)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59                    1                                   1                                                            
/**
 * @fileoverview Rule to flag use of an lexical declarations inside a case clause
 * @author Erik Arvidsson
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow lexical declarations in case clauses",
            category: "Best Practices",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
 
        /**
         * Checks whether or not a node is a lexical declaration.
         * @param {ASTNode} node A direct child statement of a switch case.
         * @returns {boolean} Whether or not the node is a lexical declaration.
         */
        function isLexicalDeclaration(node) {
            switch (node.type) {
                case "FunctionDeclaration":
                case "ClassDeclaration":
                    return true;
                case "VariableDeclaration":
                    return node.kind !== "var";
                default:
                    return false;
            }
        }
 
        return {
            SwitchCase(node) {
                for (let i = 0; i < node.consequent.length; i++) {
                    const statement = node.consequent[i];
 
                    if (isLexicalDeclaration(statement)) {
                        context.report({
                            node,
                            message: "Unexpected lexical declaration in case block."
                        });
                    }
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-catch-shadow.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-catch-shadow.js

Statements: 30% (3 / 10)      Branches: 0% (0 / 4)      Functions: 0% (0 / 3)      Lines: 30% (3 / 10)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69                      1           1                                             1                                                        
/**
 * @fileoverview Rule to flag variable leak in CatchClauses in IE 8 and earlier
 * @author Ian Christian Myers
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `catch` clause parameters from shadowing variables in the outer scope",
            category: "Variables",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Check if the parameters are been shadowed
         * @param {Object} scope current scope
         * @param {string} name parameter name
         * @returns {boolean} True is its been shadowed
         */
        function paramIsShadowing(scope, name) {
            return astUtils.getVariableByName(scope, name) !== null;
        }
 
        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------
 
        return {
 
            CatchClause(node) {
                let scope = context.getScope();
 
                // When blockBindings is enabled, CatchClause creates its own scope
                // so start from one upper scope to exclude the current node
                if (scope.block === node) {
                    scope = scope.upper;
                }
 
                if (paramIsShadowing(scope, node.param.name)) {
                    context.report({ node, message: "Value of '{{name}}' may be overwritten in IE 8 and earlier.", data: { name: node.param.name } });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-class-assign.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-class-assign.js

Statements: 50% (4 / 8)      Branches: 100% (0 / 0)      Functions: 0% (0 / 3)      Lines: 50% (4 / 8)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56              1           1                                   1                       1                        
/**
 * @fileoverview A rule to disallow modifying variables of class declarations
 * @author Toru Nagashima
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow reassigning class members",
            category: "ECMAScript 6",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
 
        /**
         * Finds and reports references that are non initializer and writable.
         * @param {Variable} variable - A variable to check.
         * @returns {void}
         */
        function checkVariable(variable) {
            astUtils.getModifyingReferences(variable.references).forEach(reference => {
                context.report({ node: reference.identifier, message: "'{{name}}' is a class.", data: { name: reference.identifier.name } });
 
            });
        }
 
        /**
         * Finds and reports references that are non initializer and writable.
         * @param {ASTNode} node - A ClassDeclaration/ClassExpression node to check.
         * @returns {void}
         */
        function checkForClass(node) {
            context.getDeclaredVariables(node).forEach(checkVariable);
        }
 
        return {
            ClassDeclaration: checkForClass,
            ClassExpression: checkForClass
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-compare-neg-zero.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-compare-neg-zero.js

Statements: 25% (2 / 8)      Branches: 0% (0 / 10)      Functions: 0% (0 / 3)      Lines: 25% (2 / 8)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55                    1                                             1                                          
/**
 * @fileoverview The rule should warn against code that tries to compare against -0.
 * @author Aladdin-ADD <hh_2013@foxmail.com>
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow comparing against -0",
            category: "Possible Errors",
            recommended: false
        },
        fixable: null,
        schema: []
    },
 
    create(context) {
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Checks a given node is -0
         *
         * @param {ASTNode} node - A node to check.
         * @returns {boolean} `true` if the node is -0.
         */
        function isNegZero(node) {
            return node.type === "UnaryExpression" && node.operator === "-" && node.argument.type === "Literal" && node.argument.value === 0;
        }
        const OPERATORS_TO_CHECK = new Set([">", ">=", "<", "<=", "==", "===", "!=", "!=="]);
 
        return {
            BinaryExpression(node) {
                if (OPERATORS_TO_CHECK.has(node.operator)) {
                    if (isNegZero(node.left) || isNegZero(node.right)) {
                        context.report({
                            node,
                            message: "Do not use the '{{operator}}' operator to compare against -0.",
                            data: { operator: node.operator }
                        });
                    }
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-cond-assign.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-cond-assign.js

Statements: 30.77% (8 / 26)      Branches: 0% (0 / 27)      Functions: 0% (0 / 6)      Lines: 30.77% (8 / 26)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137            1   1                     1                                                   1                     1                                 1                           1                                             1                                                    
/**
 * @fileoverview Rule to flag assignment in a conditional statement's test expression
 * @author Stephen Murray <spmurrayzzz>
 */
"use strict";
 
const astUtils = require("../ast-utils");
 
const NODE_DESCRIPTIONS = {
    DoWhileStatement: "a 'do...while' statement",
    ForStatement: "a 'for' statement",
    IfStatement: "an 'if' statement",
    WhileStatement: "a 'while' statement"
};
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow assignment operators in conditional expressions",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: [
            {
                enum: ["except-parens", "always"]
            }
        ]
    },
 
    create(context) {
 
        const prohibitAssign = (context.options[0] || "except-parens");
 
        const sourceCode = context.getSourceCode();
 
        /**
         * Check whether an AST node is the test expression for a conditional statement.
         * @param {!Object} node The node to test.
         * @returns {boolean} `true` if the node is the text expression for a conditional statement; otherwise, `false`.
         */
        function isConditionalTestExpression(node) {
            return node.parent &&
                node.parent.test &&
                node === node.parent.test;
        }
 
        /**
         * Given an AST node, perform a bottom-up search for the first ancestor that represents a conditional statement.
         * @param {!Object} node The node to use at the start of the search.
         * @returns {?Object} The closest ancestor node that represents a conditional statement.
         */
        function findConditionalAncestor(node) {
            let currentAncestor = node;
 
            do {
                if (isConditionalTestExpression(currentAncestor)) {
                    return currentAncestor.parent;
                }
            } while ((currentAncestor = currentAncestor.parent) && !astUtils.isFunction(currentAncestor));
 
            return null;
        }
 
        /**
         * Check whether the code represented by an AST node is enclosed in two sets of parentheses.
         * @param {!Object} node The node to test.
         * @returns {boolean} `true` if the code is enclosed in two sets of parentheses; otherwise, `false`.
         */
        function isParenthesisedTwice(node) {
            const previousToken = sourceCode.getTokenBefore(node, 1),
                nextToken = sourceCode.getTokenAfter(node, 1);
 
            return astUtils.isParenthesised(sourceCode, node) &&
                astUtils.isOpeningParenToken(previousToken) && previousToken.range[1] <= node.range[0] &&
                astUtils.isClosingParenToken(nextToken) && nextToken.range[0] >= node.range[1];
        }
 
        /**
         * Check a conditional statement's test expression for top-level assignments that are not enclosed in parentheses.
         * @param {!Object} node The node for the conditional statement.
         * @returns {void}
         */
        function testForAssign(node) {
            if (node.test &&
                (node.test.type === "AssignmentExpression") &&
                (node.type === "ForStatement"
                    ? !astUtils.isParenthesised(sourceCode, node.test)
                    : !isParenthesisedTwice(node.test)
                )
            ) {
 
                // must match JSHint's error message
                context.report({
                    node,
                    loc: node.test.loc.start,
                    message: "Expected a conditional expression and instead saw an assignment."
                });
            }
        }
 
        /**
         * Check whether an assignment expression is descended from a conditional statement's test expression.
         * @param {!Object} node The node for the assignment expression.
         * @returns {void}
         */
        function testForConditionalAncestor(node) {
            const ancestor = findConditionalAncestor(node);
 
            if (ancestor) {
                context.report({ node: ancestor, message: "Unexpected assignment within {{type}}.", data: {
                    type: NODE_DESCRIPTIONS[ancestor.type] || ancestor.type
                } });
            }
        }
 
        if (prohibitAssign === "always") {
            return {
                AssignmentExpression: testForConditionalAncestor
            };
        }
 
        return {
            DoWhileStatement: testForAssign,
            ForStatement: testForAssign,
            IfStatement: testForAssign,
            WhileStatement: testForAssign
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-confusing-arrow.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-confusing-arrow.js

Statements: 36.36% (4 / 11)      Branches: 0% (0 / 10)      Functions: 0% (0 / 3)      Lines: 36.36% (4 / 11)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68                1                     1               1                                                   1                            
/**
 * @fileoverview A rule to warn against using arrow functions when they could be
 * confused with comparisions
 * @author Jxck <https://github.com/Jxck>
 */
 
"use strict";
 
const astUtils = require("../ast-utils.js");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks whether or not a node is a conditional expression.
 * @param {ASTNode} node - node to test
 * @returns {boolean} `true` if the node is a conditional expression.
 */
function isConditional(node) {
    return node && node.type === "ConditionalExpression";
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow arrow functions where they could be confused with comparisons",
            category: "ECMAScript 6",
            recommended: false
        },
 
        schema: [{
            type: "object",
            properties: {
                allowParens: { type: "boolean" }
            },
            additionalProperties: false
        }]
    },
 
    create(context) {
        const config = context.options[0] || {};
        const sourceCode = context.getSourceCode();
 
        /**
         * Reports if an arrow function contains an ambiguous conditional.
         * @param {ASTNode} node - A node to check and report.
         * @returns {void}
         */
        function checkArrowFunc(node) {
            const body = node.body;
 
            if (isConditional(body) && !(config.allowParens && astUtils.isParenthesised(sourceCode, body))) {
                context.report({ node, message: "Arrow function used ambiguously with a conditional expression." });
            }
        }
 
        return {
            ArrowFunctionExpression: checkArrowFunc
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-console.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-console.js

Statements: 25% (6 / 24)      Branches: 0% (0 / 17)      Functions: 0% (0 / 6)      Lines: 25% (6 / 24)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132                      1           1                                                                       1                         1                           1                                 1                                                                    
/**
 * @fileoverview Rule to flag use of console object
 * @author Nicholas C. Zakas
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow the use of `console`",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    allow: {
                        type: "array",
                        items: {
                            type: "string"
                        },
                        minItems: 1,
                        uniqueItems: true
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const options = context.options[0] || {};
        const allowed = options.allow || [];
 
        /**
         * Checks whether the given reference is 'console' or not.
         *
         * @param {escope.Reference} reference - The reference to check.
         * @returns {boolean} `true` if the reference is 'console'.
         */
        function isConsole(reference) {
            const id = reference.identifier;
 
            return id && id.name === "console";
        }
 
        /**
         * Checks whether the property name of the given MemberExpression node
         * is allowed by options or not.
         *
         * @param {ASTNode} node - The MemberExpression node to check.
         * @returns {boolean} `true` if the property name of the node is allowed.
         */
        function isAllowed(node) {
            const propertyName = astUtils.getStaticPropertyName(node);
 
            return propertyName && allowed.indexOf(propertyName) !== -1;
        }
 
        /**
         * Checks whether the given reference is a member access which is not
         * allowed by options or not.
         *
         * @param {escope.Reference} reference - The reference to check.
         * @returns {boolean} `true` if the reference is a member access which
         *      is not allowed by options.
         */
        function isMemberAccessExceptAllowed(reference) {
            const node = reference.identifier;
            const parent = node.parent;
 
            return (
                parent.type === "MemberExpression" &&
                parent.object === node &&
                !isAllowed(parent)
            );
        }
 
        /**
         * Reports the given reference as a violation.
         *
         * @param {escope.Reference} reference - The reference to report.
         * @returns {void}
         */
        function report(reference) {
            const node = reference.identifier.parent;
 
            context.report({
                node,
                loc: node.loc,
                message: "Unexpected console statement."
            });
        }
 
        return {
            "Program:exit"() {
                const scope = context.getScope();
                const consoleVar = astUtils.getVariableByName(scope, "console");
                const shadowed = consoleVar && consoleVar.defs.length > 0;
 
                /* 'scope.through' includes all references to undefined
                 * variables. If the variable 'console' is not defined, it uses
                 * 'scope.through'.
                 */
                const references = consoleVar
                    ? consoleVar.references
                    : scope.through.filter(isConsole);
 
                if (!shadowed) {
                    references
                        .filter(isMemberAccessExceptAllowed)
                        .forEach(report);
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-const-assign.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-const-assign.js

Statements: 37.5% (3 / 8)      Branches: 0% (0 / 2)      Functions: 0% (0 / 3)      Lines: 37.5% (3 / 8)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49              1           1                                   1                                  
/**
 * @fileoverview A rule to disallow modifying variables that are declared using `const`
 * @author Toru Nagashima
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow reassigning `const` variables",
            category: "ECMAScript 6",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
 
        /**
         * Finds and reports references that are non initializer and writable.
         * @param {Variable} variable - A variable to check.
         * @returns {void}
         */
        function checkVariable(variable) {
            astUtils.getModifyingReferences(variable.references).forEach(reference => {
                context.report({ node: reference.identifier, message: "'{{name}}' is constant.", data: { name: reference.identifier.name } });
            });
        }
 
        return {
            VariableDeclaration(node) {
                if (node.kind === "const") {
                    context.getDeclaredVariables(node).forEach(checkVariable);
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-constant-condition.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-constant-condition.js

Statements: 16.67% (5 / 30)      Branches: 0% (0 / 47)      Functions: 0% (0 / 5)      Lines: 16.67% (5 / 30)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156                      1                                                                         1                                                   1                                                                                               1                       1                                          
/**
 * @fileoverview Rule to flag use constant conditions
 * @author Christian Schulz <http://rndm.de>
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow constant expressions in conditions",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    checkLoops: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
 
        ]
    },
 
    create(context) {
        const options = context.options[0] || {},
            checkLoops = options.checkLoops !== false;
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
 
        /**
         * Checks if a branch node of LogicalExpression short circuits the whole condition
         * @param {ASTNode} node The branch of main condition which needs to be checked
         * @param {string} operator The operator of the main LogicalExpression.
         * @returns {boolean} true when condition short circuits whole condition
         */
        function isLogicalIdentity(node, operator) {
            switch (node.type) {
                case "Literal":
                    return (operator === "||" && node.value === true) ||
                           (operator === "&&" && node.value === false);
 
                case "UnaryExpression":
                    return (operator === "&&" && node.operator === "void");
 
                case "LogicalExpression":
                    return isLogicalIdentity(node.left, node.operator) ||
                             isLogicalIdentity(node.right, node.operator);
 
                // no default
            }
            return false;
        }
 
        /**
         * Checks if a node has a constant truthiness value.
         * @param {ASTNode} node The AST node to check.
         * @param {boolean} inBooleanPosition `false` if checking branch of a condition.
         *  `true` in all other cases
         * @returns {Bool} true when node's truthiness is constant
         * @private
         */
        function isConstant(node, inBooleanPosition) {
            switch (node.type) {
                case "Literal":
                case "ArrowFunctionExpression":
                case "FunctionExpression":
                case "ObjectExpression":
                case "ArrayExpression":
                    return true;
 
                case "UnaryExpression":
                    if (node.operator === "void") {
                        return true;
                    }
 
                    return (node.operator === "typeof" && inBooleanPosition) ||
                        isConstant(node.argument, true);
 
                case "BinaryExpression":
                    return isConstant(node.left, false) &&
                            isConstant(node.right, false) &&
                            node.operator !== "in";
 
                case "LogicalExpression": {
                    const isLeftConstant = isConstant(node.left, inBooleanPosition);
                    const isRightConstant = isConstant(node.right, inBooleanPosition);
                    const isLeftShortCircuit = (isLeftConstant && isLogicalIdentity(node.left, node.operator));
                    const isRightShortCircuit = (isRightConstant && isLogicalIdentity(node.right, node.operator));
 
                    return (isLeftConstant && isRightConstant) || isLeftShortCircuit || isRightShortCircuit;
                }
 
                case "AssignmentExpression":
                    return (node.operator === "=") && isConstant(node.right, inBooleanPosition);
 
                case "SequenceExpression":
                    return isConstant(node.expressions[node.expressions.length - 1], inBooleanPosition);
 
                // no default
            }
            return false;
        }
 
        /**
         * Reports when the given node contains a constant condition.
         * @param {ASTNode} node The AST node to check.
         * @returns {void}
         * @private
         */
        function checkConstantCondition(node) {
            if (node.test && isConstant(node.test, true)) {
                context.report({ node, message: "Unexpected constant condition." });
            }
        }
 
        /**
         * Checks node when checkLoops option is enabled
         * @param {ASTNode} node The AST node to check.
         * @returns {void}
         * @private
         */
        function checkLoop(node) {
            if (checkLoops) {
                checkConstantCondition(node);
            }
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            ConditionalExpression: checkConstantCondition,
            IfStatement: checkConstantCondition,
            WhileStatement: checkLoop,
            DoWhileStatement: checkLoop,
            ForStatement: checkLoop
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-continue.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-continue.js

Statements: 33.33% (1 / 3)      Branches: 100% (0 / 0)      Functions: 0% (0 / 2)      Lines: 33.33% (1 / 3)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34                      1                                            
/**
 * @fileoverview Rule to flag use of continue statement
 * @author Borislav Zhivkov
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `continue` statements",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
            ContinueStatement(node) {
                context.report({ node, message: "Unexpected use of continue statement." });
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-control-regex.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-control-regex.js

Statements: 8.11% (3 / 37)      Branches: 0% (0 / 24)      Functions: 0% (0 / 4)      Lines: 8.11% (3 / 37)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128                      1                                     1                                                                       1                                                                                                                          
/**
 * @fileoverview Rule to forbid control charactes from regular expressions.
 * @author Nicholas C. Zakas
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow control characters in regular expressions",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
 
        /**
         * Get the regex expression
         * @param {ASTNode} node node to evaluate
         * @returns {*} Regex if found else null
         * @private
         */
        function getRegExp(node) {
            if (node.value instanceof RegExp) {
                return node.value;
            } else if (typeof node.value === "string") {
 
                const parent = context.getAncestors().pop();
 
                if ((parent.type === "NewExpression" || parent.type === "CallExpression") &&
                    parent.callee.type === "Identifier" && parent.callee.name === "RegExp"
                ) {
 
                    // there could be an invalid regular expression string
                    try {
                        return new RegExp(node.value);
                    } catch (ex) {
                        return null;
                    }
                }
            }
 
            return null;
        }
 
 
        const controlChar = /[\x00-\x1f]/g; // eslint-disable-line no-control-regex
        const consecutiveSlashes = /\\+/g;
        const consecutiveSlashesAtEnd = /\\+$/g;
        const stringControlChar = /\\x[01][0-9a-f]/ig;
        const stringControlCharWithoutSlash = /x[01][0-9a-f]/ig;
 
        /**
         * Return a list of the control characters in the given regex string
         * @param {string} regexStr regex as string to check
         * @returns {array} returns a list of found control characters on given string
         * @private
         */
        function getControlCharacters(regexStr) {
 
            // check control characters, if RegExp object used
            const controlChars = regexStr.match(controlChar) || [];
 
            let stringControlChars = [];
 
            // check substr, if regex literal used
            const subStrIndex = regexStr.search(stringControlChar);
 
            if (subStrIndex > -1) {
 
                // is it escaped, check backslash count
                const possibleEscapeCharacters = regexStr.slice(0, subStrIndex).match(consecutiveSlashesAtEnd);
 
                const hasControlChars = possibleEscapeCharacters === null || !(possibleEscapeCharacters[0].length % 2);
 
                if (hasControlChars) {
                    stringControlChars = regexStr.slice(subStrIndex, -1)
                        .split(consecutiveSlashes)
                        .filter(Boolean)
                        .map(x => {
                            const match = x.match(stringControlCharWithoutSlash) || [x];
 
                            return `\\${match[0]}`;
                        });
                }
            }
 
            return controlChars.map(x => {
                const hexCode = `0${x.charCodeAt(0).toString(16)}`.slice(-2);
 
                return `\\x${hexCode}`;
            }).concat(stringControlChars);
        }
 
        return {
            Literal(node) {
                const regex = getRegExp(node);
 
                if (regex) {
                    const computedValue = regex.toString();
 
                    const controlCharacters = getControlCharacters(computedValue);
 
                    if (controlCharacters.length > 0) {
                        context.report({
                            node,
                            message: "Unexpected control character(s) in regular expression: {{controlChars}}.",
                            data: {
                                controlChars: controlCharacters.join(", ")
                            }
                        });
                    }
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-debugger.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-debugger.js

Statements: 33.33% (1 / 3)      Branches: 100% (0 / 0)      Functions: 0% (0 / 2)      Lines: 33.33% (1 / 3)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34                      1                                            
/**
 * @fileoverview Rule to flag use of a debugger statement
 * @author Nicholas C. Zakas
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow the use of `debugger`",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
            DebuggerStatement(node) {
                context.report({ node, message: "Unexpected 'debugger' statement." });
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-delete-var.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-delete-var.js

Statements: 25% (1 / 4)      Branches: 0% (0 / 4)      Functions: 0% (0 / 2)      Lines: 25% (1 / 4)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37                      1                                                  
/**
 * @fileoverview Rule to flag when deleting variables
 * @author Ilya Volodin
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow deleting variables",
            category: "Variables",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
 
            UnaryExpression(node) {
                if (node.operator === "delete" && node.argument.type === "Identifier") {
                    context.report({ node, message: "Variables should not be deleted." });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-div-regex.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-div-regex.js

Statements: 16.67% (1 / 6)      Branches: 0% (0 / 4)      Functions: 0% (0 / 2)      Lines: 16.67% (1 / 6)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40                      1                                                        
/**
 * @fileoverview Rule to check for ambiguous div operator in regexes
 * @author Matt DuVall <http://www.mattduvall.com>
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow division operators explicitly at the beginning of regular expressions",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        return {
 
            Literal(node) {
                const token = sourceCode.getFirstToken(node);
 
                if (token.type === "RegularExpression" && token.value[1] === "=") {
                    context.report({ node, message: "A regular expression literal can be confused with '/='." });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-dupe-args.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-dupe-args.js

Statements: 27.27% (3 / 11)      Branches: 0% (0 / 2)      Functions: 0% (0 / 3)      Lines: 27.27% (3 / 11)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75                      1                                           1                   1                                                              
/**
 * @fileoverview Rule to flag duplicate arguments
 * @author Jamund Ferguson
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow duplicate arguments in `function` definitions",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Checks whether or not a given definition is a parameter's.
         * @param {escope.DefEntry} def - A definition to check.
         * @returns {boolean} `true` if the definition is a parameter's.
         */
        function isParameter(def) {
            return def.type === "Parameter";
        }
 
        /**
         * Determines if a given node has duplicate parameters.
         * @param {ASTNode} node The node to check.
         * @returns {void}
         * @private
         */
        function checkParams(node) {
            const variables = context.getDeclaredVariables(node);
 
            for (let i = 0; i < variables.length; ++i) {
                const variable = variables[i];
 
                // Checks and reports duplications.
                const defs = variable.defs.filter(isParameter);
 
                if (defs.length >= 2) {
                    context.report({
                        node,
                        message: "Duplicate param '{{name}}'.",
                        data: { name: variable.name }
                    });
                }
            }
        }
 
        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------
 
        return {
            FunctionDeclaration: checkParams,
            FunctionExpression: checkParams
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-dupe-class-members.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-dupe-class-members.js

Statements: 12.5% (4 / 32)      Branches: 4.55% (1 / 22)      Functions: 0% (0 / 7)      Lines: 12.5% (4 / 32)      Ignored: 1 statement, 1 branch     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111                      1                                             1                                       1           1                                                                                                    
/**
 * @fileoverview A rule to disallow duplicate name in class members.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow duplicate class members",
            category: "ECMAScript 6",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
        let stack = [];
 
        /**
         * Gets state of a given member name.
         * @param {string} name - A name of a member.
         * @param {boolean} isStatic - A flag which specifies that is a static member.
         * @returns {Object} A state of a given member name.
         *   - retv.init {boolean} A flag which shows the name is declared as normal member.
         *   - retv.get {boolean} A flag which shows the name is declared as getter.
         *   - retv.set {boolean} A flag which shows the name is declared as setter.
         */
        function getState(name, isStatic) {
            const stateMap = stack[stack.length - 1];
            const key = `$${name}`; // to avoid "__proto__".
 
            if (!stateMap[key]) {
                stateMap[key] = {
                    nonStatic: { init: false, get: false, set: false },
                    static: { init: false, get: false, set: false }
                };
            }
 
            return stateMap[key][isStatic ? "static" : "nonStatic"];
        }
 
        /**
         * Gets the name text of a given node.
         *
         * @param {ASTNode} node - A node to get the name.
         * @returns {string} The name text of the node.
         */
        function getName(node) {
            switch (node.type) {
                case "Identifier": return node.name;
                case "Literal": return String(node.value);
 
                /* istanbul ignore next: syntax error */
                default: return "";
            }
        }
 
        return {
 
            // Initializes the stack of state of member declarations.
            Program() {
                stack = [];
            },
 
            // Initializes state of member declarations for the class.
            ClassBody() {
                stack.push(Object.create(null));
            },
 
            // Disposes the state for the class.
            "ClassBody:exit"() {
                stack.pop();
            },
 
            // Reports the node if its name has been declared already.
            MethodDefinition(node) {
                if (node.computed) {
                    return;
                }
 
                const name = getName(node.key);
                const state = getState(name, node.static);
                let isDuplicate = false;
 
                if (node.kind === "get") {
                    isDuplicate = (state.init || state.get);
                    state.get = true;
                } else if (node.kind === "set") {
                    isDuplicate = (state.init || state.set);
                    state.set = true;
                } else {
                    isDuplicate = (state.init || state.get || state.set);
                    state.init = true;
                }
 
                if (isDuplicate) {
                    context.report({ node, message: "Duplicate name '{{name}}'.", data: { name } });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-dupe-keys.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-dupe-keys.js

Statements: 13.33% (4 / 30)      Branches: 0% (0 / 16)      Functions: 0% (0 / 8)      Lines: 13.33% (4 / 30)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137                      1           1 1                                                                                                                                   1                                                                                                        
/**
 * @fileoverview Rule to flag use of duplicate keys in an object.
 * @author Ian Christian Myers
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const GET_KIND = /^(?:init|get)$/;
const SET_KIND = /^(?:init|set)$/;
 
/**
 * The class which stores properties' information of an object.
 */
class ObjectInfo {
 
    /**
     * @param {ObjectInfo|null} upper - The information of the outer object.
     * @param {ASTNode} node - The ObjectExpression node of this information.
     */
    constructor(upper, node) {
        this.upper = upper;
        this.node = node;
        this.properties = new Map();
    }
 
    /**
     * Gets the information of the given Property node.
     * @param {ASTNode} node - The Property node to get.
     * @returns {{get: boolean, set: boolean}} The information of the property.
     */
    getPropertyInfo(node) {
        const name = astUtils.getStaticPropertyName(node);
 
        if (!this.properties.has(name)) {
            this.properties.set(name, { get: false, set: false });
        }
        return this.properties.get(name);
    }
 
    /**
     * Checks whether the given property has been defined already or not.
     * @param {ASTNode} node - The Property node to check.
     * @returns {boolean} `true` if the property has been defined.
     */
    isPropertyDefined(node) {
        const entry = this.getPropertyInfo(node);
 
        return (
            (GET_KIND.test(node.kind) && entry.get) ||
            (SET_KIND.test(node.kind) && entry.set)
        );
    }
 
    /**
     * Defines the given property.
     * @param {ASTNode} node - The Property node to define.
     * @returns {void}
     */
    defineProperty(node) {
        const entry = this.getPropertyInfo(node);
 
        if (GET_KIND.test(node.kind)) {
            entry.get = true;
        }
        if (SET_KIND.test(node.kind)) {
            entry.set = true;
        }
    }
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow duplicate keys in object literals",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
        let info = null;
 
        return {
            ObjectExpression(node) {
                info = new ObjectInfo(info, node);
            },
            "ObjectExpression:exit"() {
                info = info.upper;
            },
 
            Property(node) {
                const name = astUtils.getStaticPropertyName(node);
 
                // Skip destructuring.
                if (node.parent.type !== "ObjectExpression") {
                    return;
                }
 
                // Skip if the name is not static.
                if (!name) {
                    return;
                }
 
                // Reports if the name is defined already.
                if (info.isPropertyDefined(node)) {
                    context.report({
                        node: info.node,
                        loc: node.key.loc,
                        message: "Duplicate key '{{name}}'.",
                        data: { name }
                    });
                }
 
                // Update info.
                info.defineProperty(node);
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-duplicate-case.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-duplicate-case.js

Statements: 11.11% (1 / 9)      Branches: 0% (0 / 2)      Functions: 0% (0 / 2)      Lines: 11.11% (1 / 9)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45                        1                                                                
/**
 * @fileoverview Rule to disallow a duplicate case label.
 * @author Dieter Oberkofler
 * @author Burak Yigit Kaya
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow duplicate case labels",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        return {
            SwitchStatement(node) {
                const mapping = {};
 
                node.cases.forEach(switchCase => {
                    const key = sourceCode.getText(switchCase.test);
 
                    if (mapping[key]) {
                        context.report({ node: switchCase, message: "Duplicate case label." });
                    } else {
                        mapping[key] = switchCase;
                    }
                });
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-duplicate-imports.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-duplicate-imports.js

Statements: 17.24% (5 / 29)      Branches: 0% (0 / 17)      Functions: 0% (0 / 7)      Lines: 17.24% (5 / 29)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139                                1                                     1                                                       1                                                 1                         1                                                                          
/**
 * @fileoverview Restrict usage of duplicate imports.
 * @author Simen Bekkhus
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
/**
 * Returns the name of the module imported or re-exported.
 *
 * @param {ASTNode} node - A node to get.
 * @returns {string} the name of the module, or empty string if no name.
 */
function getValue(node) {
    if (node && node.source && node.source.value) {
        return node.source.value.trim();
    }
 
    return "";
}
 
/**
 * Checks if the name of the import or export exists in the given array, and reports if so.
 *
 * @param {RuleContext} context - The ESLint rule context object.
 * @param {ASTNode} node - A node to get.
 * @param {string} value - The name of the imported or exported module.
 * @param {string[]} array - The array containing other imports or exports in the file.
 * @param {string} message - A message to be reported after the name of the module
 *
 * @returns {void} No return value
 */
function checkAndReport(context, node, value, array, message) {
    if (array.indexOf(value) !== -1) {
        context.report({
            node,
            message: "'{{module}}' {{message}}",
            data: {
                module: value,
                message
            }
        });
    }
}
 
/**
 * @callback nodeCallback
 * @param {ASTNode} node - A node to handle.
 */
 
/**
 * Returns a function handling the imports of a given file
 *
 * @param {RuleContext} context - The ESLint rule context object.
 * @param {boolean} includeExports - Whether or not to check for exports in addition to imports.
 * @param {string[]} importsInFile - The array containing other imports in the file.
 * @param {string[]} exportsInFile - The array containing other exports in the file.
 *
 * @returns {nodeCallback} A function passed to ESLint to handle the statement.
 */
function handleImports(context, includeExports, importsInFile, exportsInFile) {
    return function(node) {
        const value = getValue(node);
 
        if (value) {
            checkAndReport(context, node, value, importsInFile, "import is duplicated.");
 
            if (includeExports) {
                checkAndReport(context, node, value, exportsInFile, "import is duplicated as export.");
            }
 
            importsInFile.push(value);
        }
    };
}
 
/**
 * Returns a function handling the exports of a given file
 *
 * @param {RuleContext} context - The ESLint rule context object.
 * @param {string[]} importsInFile - The array containing other imports in the file.
 * @param {string[]} exportsInFile - The array containing other exports in the file.
 *
 * @returns {nodeCallback} A function passed to ESLint to handle the statement.
 */
function handleExports(context, importsInFile, exportsInFile) {
    return function(node) {
        const value = getValue(node);
 
        if (value) {
            checkAndReport(context, node, value, exportsInFile, "export is duplicated.");
            checkAndReport(context, node, value, importsInFile, "export is duplicated as import.");
 
            exportsInFile.push(value);
        }
    };
}
 
module.exports = {
    meta: {
        docs: {
            description: "disallow duplicate module imports",
            category: "ECMAScript 6",
            recommended: false
        },
 
        schema: [{
            type: "object",
            properties: {
                includeExports: {
                    type: "boolean"
                }
            },
            additionalProperties: false
        }]
    },
 
    create(context) {
        const includeExports = (context.options[0] || {}).includeExports,
            importsInFile = [],
            exportsInFile = [];
 
        const handlers = {
            ImportDeclaration: handleImports(context, includeExports, importsInFile, exportsInFile)
        };
 
        if (includeExports) {
            handlers.ExportNamedDeclaration = handleExports(context, importsInFile, exportsInFile);
            handlers.ExportAllDeclaration = handleExports(context, importsInFile, exportsInFile);
        }
 
        return handlers;
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-else-return.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-else-return.js

Statements: 18.33% (11 / 60)      Branches: 0% (0 / 46)      Functions: 0% (0 / 9)      Lines: 18.33% (11 / 60)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237                      1 1           1                                                 1                                                                                                                                         1                       1                                 1                       1                           1                   1                                       1                                                                              
/**
 * @fileoverview Rule to flag `else` after a `return` in `if`
 * @author Ian Christian Myers
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
const FixTracker = require("../util/fix-tracker");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `else` blocks after `return` statements in `if` statements",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [],
 
        fixable: "code"
    },
 
    create(context) {
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Display the context report if rule is violated
         *
         * @param {Node} node The 'else' node
         * @returns {void}
         */
        function displayReport(node) {
            context.report({
                node,
                message: "Unnecessary 'else' after 'return'.",
                fix: fixer => {
                    const sourceCode = context.getSourceCode();
                    const startToken = sourceCode.getFirstToken(node);
                    const elseToken = sourceCode.getTokenBefore(startToken);
                    const source = sourceCode.getText(node);
                    const lastIfToken = sourceCode.getTokenBefore(elseToken);
                    let fixedSource, firstTokenOfElseBlock;
 
                    if (startToken.type === "Punctuator" && startToken.value === "{") {
                        firstTokenOfElseBlock = sourceCode.getTokenAfter(startToken);
                    } else {
                        firstTokenOfElseBlock = startToken;
                    }
 
                    // If the if block does not have curly braces and does not end in a semicolon
                    // and the else block starts with (, [, /, +, ` or -, then it is not
                    // safe to remove the else keyword, because ASI will not add a semicolon
                    // after the if block
                    const ifBlockMaybeUnsafe = node.parent.consequent.type !== "BlockStatement" && lastIfToken.value !== ";";
                    const elseBlockUnsafe = /^[([/+`-]/.test(firstTokenOfElseBlock.value);
 
                    if (ifBlockMaybeUnsafe && elseBlockUnsafe) {
                        return null;
                    }
 
                    const endToken = sourceCode.getLastToken(node);
                    const lastTokenOfElseBlock = sourceCode.getTokenBefore(endToken);
 
                    if (lastTokenOfElseBlock.value !== ";") {
                        const nextToken = sourceCode.getTokenAfter(endToken);
 
                        const nextTokenUnsafe = nextToken && /^[([/+`-]/.test(nextToken.value);
                        const nextTokenOnSameLine = nextToken && nextToken.loc.start.line === lastTokenOfElseBlock.loc.start.line;
 
                        // If the else block contents does not end in a semicolon,
                        // and the else block starts with (, [, /, +, ` or -, then it is not
                        // safe to remove the else block, because ASI will not add a semicolon
                        // after the remaining else block contents
                        if (nextTokenUnsafe || (nextTokenOnSameLine && nextToken.value !== "}")) {
                            return null;
                        }
                    }
 
                    if (startToken.type === "Punctuator" && startToken.value === "{") {
                        fixedSource = source.slice(1, -1);
                    } else {
                        fixedSource = source;
                    }
 
                    // Extend the replacement range to include the entire
                    // function to avoid conflicting with no-useless-return.
                    // https://github.com/eslint/eslint/issues/8026
                    return new FixTracker(fixer, sourceCode)
                        .retainEnclosingFunction(node)
                        .replaceTextRange([elseToken.start, node.end], fixedSource);
                }
            });
        }
 
        /**
         * Check to see if the node is a ReturnStatement
         *
         * @param {Node} node The node being evaluated
         * @returns {boolean} True if node is a return
         */
        function checkForReturn(node) {
            return node.type === "ReturnStatement";
        }
 
        /**
         * Naive return checking, does not iterate through the whole
         * BlockStatement because we make the assumption that the ReturnStatement
         * will be the last node in the body of the BlockStatement.
         *
         * @param {Node} node The consequent/alternate node
         * @returns {boolean} True if it has a return
         */
        function naiveHasReturn(node) {
            if (node.type === "BlockStatement") {
                const body = node.body,
                    lastChildNode = body[body.length - 1];
 
                return lastChildNode && checkForReturn(lastChildNode);
            }
            return checkForReturn(node);
        }
 
        /**
         * Check to see if the node is valid for evaluation,
         * meaning it has an else and not an else-if
         *
         * @param {Node} node The node being evaluated
         * @returns {boolean} True if the node is valid
         */
        function hasElse(node) {
            return node.alternate && node.consequent && node.alternate.type !== "IfStatement";
        }
 
        /**
         * If the consequent is an IfStatement, check to see if it has an else
         * and both its consequent and alternate path return, meaning this is
         * a nested case of rule violation.  If-Else not considered currently.
         *
         * @param {Node} node The consequent node
         * @returns {boolean} True if this is a nested rule violation
         */
        function checkForIf(node) {
            return node.type === "IfStatement" && hasElse(node) &&
                naiveHasReturn(node.alternate) && naiveHasReturn(node.consequent);
        }
 
        /**
         * Check the consequent/body node to make sure it is not
         * a ReturnStatement or an IfStatement that returns on both
         * code paths.
         *
         * @param {Node} node The consequent or body node
         * @param {Node} alternate The alternate node
         * @returns {boolean} `true` if it is a Return/If node that always returns.
         */
        function checkForReturnOrIf(node) {
            return checkForReturn(node) || checkForIf(node);
        }
 
 
        /**
         * Check whether a node returns in every codepath.
         * @param {Node} node The node to be checked
         * @returns {boolean} `true` if it returns on every codepath.
         */
        function alwaysReturns(node) {
            if (node.type === "BlockStatement") {
 
                // If we have a BlockStatement, check each consequent body node.
                return node.body.some(checkForReturnOrIf);
            }
 
            /*
             * If not a block statement, make sure the consequent isn't a
             * ReturnStatement or an IfStatement with returns on both paths.
             */
            return checkForReturnOrIf(node);
        }
 
        /**
         * Check the if statement
         * @returns {void}
         * @param {Node} node The node for the if statement to check
         * @private
         */
        function IfStatement(node) {
            const parent = context.getAncestors().pop();
            let consequents,
                alternate;
 
            /*
             * Fixing this would require splitting one statement into two, so no error should
             * be reported if this node is in a position where only one statement is allowed.
             */
            if (!astUtils.STATEMENT_LIST_PARENTS.has(parent.type)) {
                return;
            }
 
            for (consequents = []; node.type === "IfStatement"; node = node.alternate) {
                if (!node.alternate) {
                    return;
                }
                consequents.push(node.consequent);
                alternate = node.alternate;
            }
 
            if (consequents.every(alwaysReturns)) {
                displayReport(alternate);
            }
        }
 
        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------
 
        return {
 
            "IfStatement:exit": IfStatement
 
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-empty-character-class.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-empty-character-class.js

Statements: 28.57% (2 / 7)      Branches: 0% (0 / 4)      Functions: 0% (0 / 2)      Lines: 28.57% (2 / 7)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59                                              1           1                                                          
/**
 * @fileoverview Rule to flag the use of empty character classes in regular expressions
 * @author Ian Christian Myers
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/*
plain-English description of the following regexp:
0. `^` fix the match at the beginning of the string
1. `\/`: the `/` that begins the regexp
2. `([^\\[]|\\.|\[([^\\\]]|\\.)+\])*`: regexp contents; 0 or more of the following
  2.0. `[^\\[]`: any character that's not a `\` or a `[` (anything but escape sequences and character classes)
  2.1. `\\.`: an escape sequence
  2.2. `\[([^\\\]]|\\.)+\]`: a character class that isn't empty
3. `\/` the `/` that ends the regexp
4. `[gimuy]*`: optional regexp flags
5. `$`: fix the match at the end of the string
*/
const regex = /^\/([^\\[]|\\.|\[([^\\\]]|\\.)+])*\/[gimuy]*$/;
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow empty character classes in regular expressions",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        return {
 
            Literal(node) {
                const token = sourceCode.getFirstToken(node);
 
                if (token.type === "RegularExpression" && !regex.test(token.value)) {
                    context.report({ node, message: "Empty class." });
                }
            }
 
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-empty-function.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-empty-function.js

Statements: 12.82% (5 / 39)      Branches: 0% (0 / 32)      Functions: 0% (0 / 3)      Lines: 12.82% (5 / 39)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158                      1           1                                           1                                                                                                     1                                                                                 1                                                    
/**
 * @fileoverview Rule to disallow empty functions.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const ALLOW_OPTIONS = Object.freeze([
    "functions",
    "arrowFunctions",
    "generatorFunctions",
    "methods",
    "generatorMethods",
    "getters",
    "setters",
    "constructors"
]);
 
/**
 * Gets the kind of a given function node.
 *
 * @param {ASTNode} node - A function node to get. This is one of
 *      an ArrowFunctionExpression, a FunctionDeclaration, or a
 *      FunctionExpression.
 * @returns {string} The kind of the function. This is one of "functions",
 *      "arrowFunctions", "generatorFunctions", "asyncFunctions", "methods",
 *      "generatorMethods", "asyncMethods", "getters", "setters", and
 *      "constructors".
 */
function getKind(node) {
    const parent = node.parent;
    let kind = "";
 
    if (node.type === "ArrowFunctionExpression") {
        return "arrowFunctions";
    }
 
    // Detects main kind.
    if (parent.type === "Property") {
        if (parent.kind === "get") {
            return "getters";
        }
        if (parent.kind === "set") {
            return "setters";
        }
        kind = parent.method ? "methods" : "functions";
 
    } else if (parent.type === "MethodDefinition") {
        if (parent.kind === "get") {
            return "getters";
        }
        if (parent.kind === "set") {
            return "setters";
        }
        if (parent.kind === "constructor") {
            return "constructors";
        }
        kind = "methods";
 
    } else {
        kind = "functions";
    }
 
    // Detects prefix.
    let prefix = "";
 
    if (node.generator) {
        prefix = "generator";
    } else if (node.async) {
        prefix = "async";
    } else {
        return kind;
    }
    return prefix + kind[0].toUpperCase() + kind.slice(1);
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow empty functions",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    allow: {
                        type: "array",
                        items: { enum: ALLOW_OPTIONS },
                        uniqueItems: true
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const options = context.options[0] || {};
        const allowed = options.allow || [];
 
        const sourceCode = context.getSourceCode();
 
        /**
         * Reports a given function node if the node matches the following patterns.
         *
         * - Not allowed by options.
         * - The body is empty.
         * - The body doesn't have any comments.
         *
         * @param {ASTNode} node - A function node to report. This is one of
         *      an ArrowFunctionExpression, a FunctionDeclaration, or a
         *      FunctionExpression.
         * @returns {void}
         */
        function reportIfEmpty(node) {
            const kind = getKind(node);
            const name = astUtils.getFunctionNameWithKind(node);
 
            if (allowed.indexOf(kind) === -1 &&
                node.body.type === "BlockStatement" &&
                node.body.body.length === 0 &&
                sourceCode.getComments(node.body).trailing.length === 0
            ) {
                context.report({
                    node,
                    loc: node.body.loc.start,
                    message: "Unexpected empty {{name}}.",
                    data: { name }
                });
            }
        }
 
        return {
            ArrowFunctionExpression: reportIfEmpty,
            FunctionDeclaration: reportIfEmpty,
            FunctionExpression: reportIfEmpty
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-empty-pattern.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-empty-pattern.js

Statements: 16.67% (1 / 6)      Branches: 0% (0 / 4)      Functions: 0% (0 / 3)      Lines: 16.67% (1 / 6)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38                    1                                                      
/**
 * @fileoverview Rule to disallow an empty pattern
 * @author Alberto Rodríguez
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow empty destructuring patterns",
            category: "Best Practices",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
        return {
            ObjectPattern(node) {
                if (node.properties.length === 0) {
                    context.report({ node, message: "Unexpected empty object pattern." });
                }
            },
            ArrayPattern(node) {
                if (node.elements.length === 0) {
                    context.report({ node, message: "Unexpected empty array pattern." });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-empty.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-empty.js

Statements: 12.5% (2 / 16)      Branches: 0% (0 / 18)      Functions: 0% (0 / 3)      Lines: 12.5% (2 / 16)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80                    1           1                                                                                                                              
/**
 * @fileoverview Rule to flag use of an empty block statement
 * @author Nicholas C. Zakas
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow empty block statements",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    allowEmptyCatch: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const options = context.options[0] || {},
            allowEmptyCatch = options.allowEmptyCatch || false;
 
        const sourceCode = context.getSourceCode();
 
        return {
            BlockStatement(node) {
 
                // if the body is not empty, we can just return immediately
                if (node.body.length !== 0) {
                    return;
                }
 
                // a function is generally allowed to be empty
                if (astUtils.isFunction(node.parent)) {
                    return;
                }
 
                if (allowEmptyCatch && node.parent.type === "CatchClause") {
                    return;
                }
 
                // any other block is only allowed to be empty, if it contains a comment
                if (sourceCode.getComments(node).trailing.length > 0) {
                    return;
                }
 
                context.report({ node, message: "Empty block statement." });
            },
 
            SwitchStatement(node) {
 
                if (typeof node.cases === "undefined" || node.cases.length === 0) {
                    context.report({ node, message: "Empty switch statement." });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-eq-null.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-eq-null.js

Statements: 20% (1 / 5)      Branches: 0% (0 / 10)      Functions: 0% (0 / 2)      Lines: 20% (1 / 5)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41                        1                                                        
/**
 * @fileoverview Rule to flag comparisons to null without a type-checking
 * operator.
 * @author Ian Christian Myers
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `null` comparisons without type-checking operators",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
 
            BinaryExpression(node) {
                const badOperator = node.operator === "==" || node.operator === "!=";
 
                if (node.right.type === "Literal" && node.right.raw === "null" && badOperator ||
                        node.left.type === "Literal" && node.left.raw === "null" && badOperator) {
                    context.report({ node, message: "Use ‘===’ to compare with ‘null’." });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-eval.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-eval.js

Statements: 14.86% (11 / 74)      Branches: 0% (0 / 49)      Functions: 0% (0 / 14)      Lines: 14.86% (11 / 74)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310                      1           1                       1                     1                                                 1                     1                                                                         1                                 1                                 1                                               1                                                                   1                                                                                                                                                                                                                
/**
 * @fileoverview Rule to flag use of eval() statement
 * @author Nicholas C. Zakas
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const candidatesOfGlobalObject = Object.freeze([
    "global",
    "window"
]);
 
/**
 * Checks a given node is a Identifier node of the specified name.
 *
 * @param {ASTNode} node - A node to check.
 * @param {string} name - A name to check.
 * @returns {boolean} `true` if the node is a Identifier node of the name.
 */
function isIdentifier(node, name) {
    return node.type === "Identifier" && node.name === name;
}
 
/**
 * Checks a given node is a Literal node of the specified string value.
 *
 * @param {ASTNode} node - A node to check.
 * @param {string} name - A name to check.
 * @returns {boolean} `true` if the node is a Literal node of the name.
 */
function isConstant(node, name) {
    switch (node.type) {
        case "Literal":
            return node.value === name;
 
        case "TemplateLiteral":
            return (
                node.expressions.length === 0 &&
                node.quasis[0].value.cooked === name
            );
 
        default:
            return false;
    }
}
 
/**
 * Checks a given node is a MemberExpression node which has the specified name's
 * property.
 *
 * @param {ASTNode} node - A node to check.
 * @param {string} name - A name to check.
 * @returns {boolean} `true` if the node is a MemberExpression node which has
 *      the specified name's property
 */
function isMember(node, name) {
    return (
        node.type === "MemberExpression" &&
        (node.computed ? isConstant : isIdentifier)(node.property, name)
    );
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow the use of `eval()`",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    allowIndirect: { type: "boolean" }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const allowIndirect = Boolean(
            context.options[0] &&
            context.options[0].allowIndirect
        );
        const sourceCode = context.getSourceCode();
        let funcInfo = null;
 
        /**
         * Pushs a variable scope (Program or Function) information to the stack.
         *
         * This is used in order to check whether or not `this` binding is a
         * reference to the global object.
         *
         * @param {ASTNode} node - A node of the scope. This is one of Program,
         *      FunctionDeclaration, FunctionExpression, and ArrowFunctionExpression.
         * @returns {void}
         */
        function enterVarScope(node) {
            const strict = context.getScope().isStrict;
 
            funcInfo = {
                upper: funcInfo,
                node,
                strict,
                defaultThis: false,
                initialized: strict
            };
        }
 
        /**
         * Pops a variable scope from the stack.
         *
         * @returns {void}
         */
        function exitVarScope() {
            funcInfo = funcInfo.upper;
        }
 
        /**
         * Reports a given node.
         *
         * `node` is `Identifier` or `MemberExpression`.
         * The parent of `node` might be `CallExpression`.
         *
         * The location of the report is always `eval` `Identifier` (or possibly
         * `Literal`). The type of the report is `CallExpression` if the parent is
         * `CallExpression`. Otherwise, it's the given node type.
         *
         * @param {ASTNode} node - A node to report.
         * @returns {void}
         */
        function report(node) {
            let locationNode = node;
            const parent = node.parent;
 
            if (node.type === "MemberExpression") {
                locationNode = node.property;
            }
            if (parent.type === "CallExpression" && parent.callee === node) {
                node = parent;
            }
 
            context.report({
                node,
                loc: locationNode.loc.start,
                message: "eval can be harmful."
            });
        }
 
        /**
         * Reports accesses of `eval` via the global object.
         *
         * @param {escope.Scope} globalScope - The global scope.
         * @returns {void}
         */
        function reportAccessingEvalViaGlobalObject(globalScope) {
            for (let i = 0; i < candidatesOfGlobalObject.length; ++i) {
                const name = candidatesOfGlobalObject[i];
                const variable = astUtils.getVariableByName(globalScope, name);
 
                if (!variable) {
                    continue;
                }
 
                const references = variable.references;
 
                for (let j = 0; j < references.length; ++j) {
                    const identifier = references[j].identifier;
                    let node = identifier.parent;
 
                    // To detect code like `window.window.eval`.
                    while (isMember(node, name)) {
                        node = node.parent;
                    }
 
                    // Reports.
                    if (isMember(node, "eval")) {
                        report(node);
                    }
                }
            }
        }
 
        /**
         * Reports all accesses of `eval` (excludes direct calls to eval).
         *
         * @param {escope.Scope} globalScope - The global scope.
         * @returns {void}
         */
        function reportAccessingEval(globalScope) {
            const variable = astUtils.getVariableByName(globalScope, "eval");
 
            if (!variable) {
                return;
            }
 
            const references = variable.references;
 
            for (let i = 0; i < references.length; ++i) {
                const reference = references[i];
                const id = reference.identifier;
 
                if (id.name === "eval" && !astUtils.isCallee(id)) {
 
                    // Is accessing to eval (excludes direct calls to eval)
                    report(id);
                }
            }
        }
 
        if (allowIndirect) {
 
            // Checks only direct calls to eval. It's simple!
            return {
                "CallExpression:exit"(node) {
                    const callee = node.callee;
 
                    if (isIdentifier(callee, "eval")) {
                        report(callee);
                    }
                }
            };
        }
 
        return {
            "CallExpression:exit"(node) {
                const callee = node.callee;
 
                if (isIdentifier(callee, "eval")) {
                    report(callee);
                }
            },
 
            Program(node) {
                const scope = context.getScope(),
                    features = context.parserOptions.ecmaFeatures || {},
                    strict =
                        scope.isStrict ||
                        node.sourceType === "module" ||
                        (features.globalReturn && scope.childScopes[0].isStrict);
 
                funcInfo = {
                    upper: null,
                    node,
                    strict,
                    defaultThis: true,
                    initialized: true
                };
            },
 
            "Program:exit"() {
                const globalScope = context.getScope();
 
                exitVarScope();
                reportAccessingEval(globalScope);
                reportAccessingEvalViaGlobalObject(globalScope);
            },
 
            FunctionDeclaration: enterVarScope,
            "FunctionDeclaration:exit": exitVarScope,
            FunctionExpression: enterVarScope,
            "FunctionExpression:exit": exitVarScope,
            ArrowFunctionExpression: enterVarScope,
            "ArrowFunctionExpression:exit": exitVarScope,
 
            ThisExpression(node) {
                if (!isMember(node.parent, "eval")) {
                    return;
                }
 
                /*
                 * `this.eval` is found.
                 * Checks whether or not the value of `this` is the global object.
                 */
                if (!funcInfo.initialized) {
                    funcInfo.initialized = true;
                    funcInfo.defaultThis = astUtils.isDefaultThisBinding(
                        funcInfo.node,
                        sourceCode
                    );
                }
 
                if (!funcInfo.strict && funcInfo.defaultThis) {
 
                    // `this.eval` is possible built-in `eval`.
                    report(node.parent);
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-ex-assign.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-ex-assign.js

Statements: 42.86% (3 / 7)      Branches: 100% (0 / 0)      Functions: 0% (0 / 3)      Lines: 42.86% (3 / 7)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47              1           1                                   1                              
/**
 * @fileoverview Rule to flag assignment of the exception parameter
 * @author Stephen Murray <spmurrayzzz>
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow reassigning exceptions in `catch` clauses",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
 
        /**
         * Finds and reports references that are non initializer and writable.
         * @param {Variable} variable - A variable to check.
         * @returns {void}
         */
        function checkVariable(variable) {
            astUtils.getModifyingReferences(variable.references).forEach(reference => {
                context.report({ node: reference.identifier, message: "Do not assign to the exception parameter." });
            });
        }
 
        return {
            CatchClause(node) {
                context.getDeclaredVariables(node).forEach(checkVariable);
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-extend-native.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-extend-native.js

Statements: 8% (2 / 25)      Branches: 0% (0 / 32)      Functions: 0% (0 / 3)      Lines: 8.7% (2 / 23)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119                      1           1                                                                                                                                                                                                          
/**
 * @fileoverview Rule to flag adding properties to native object's prototypes.
 * @author David Nelson
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const globals = require("globals");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow extending native types",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    exceptions: {
                        type: "array",
                        items: {
                            type: "string"
                        },
                        uniqueItems: true
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        const config = context.options[0] || {};
        const exceptions = config.exceptions || [];
        let modifiedBuiltins = Object.keys(globals.builtin).filter(builtin => builtin[0].toUpperCase() === builtin[0]);
 
        if (exceptions.length) {
            modifiedBuiltins = modifiedBuiltins.filter(builtIn => exceptions.indexOf(builtIn) === -1);
        }
 
        return {
 
            // handle the Array.prototype.extra style case
            AssignmentExpression(node) {
                const lhs = node.left;
 
                if (lhs.type !== "MemberExpression" || lhs.object.type !== "MemberExpression") {
                    return;
                }
 
                const affectsProto = lhs.object.computed
                    ? lhs.object.property.type === "Literal" && lhs.object.property.value === "prototype"
                    : lhs.object.property.name === "prototype";
 
                if (!affectsProto) {
                    return;
                }
 
                modifiedBuiltins.forEach(builtin => {
                    if (lhs.object.object.name === builtin) {
                        context.report({
                            node,
                            message: "{{builtin}} prototype is read only, properties should not be added.",
                            data: {
                                builtin
                            }
                        });
                    }
                });
            },
 
            // handle the Object.definePropert[y|ies](Array.prototype) case
            CallExpression(node) {
 
                const callee = node.callee;
 
                // only worry about Object.definePropert[y|ies]
                if (callee.type === "MemberExpression" &&
                    callee.object.name === "Object" &&
                    (callee.property.name === "defineProperty" || callee.property.name === "defineProperties")) {
 
                    // verify the object being added to is a native prototype
                    const subject = node.arguments[0];
                    const object = subject && subject.object;
 
                    if (object &&
                        object.type === "Identifier" &&
                        (modifiedBuiltins.indexOf(object.name) > -1) &&
                        subject.property.name === "prototype") {
 
                        context.report({
                            node,
                            message: "{{objectName}} prototype is read only, properties should not be added.",
                            data: {
                                objectName: object.name
                            }
                        });
                    }
                }
 
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-extra-bind.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-extra-bind.js

Statements: 33.33% (8 / 24)      Branches: 0% (0 / 15)      Functions: 0% (0 / 8)      Lines: 33.33% (8 / 24)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147                    1           1                                             1                                               1                                           1                                 1                               1                     1                                  
/**
 * @fileoverview Rule to flag unnecessary bind calls
 * @author Bence Dányi <bence@danyi.me>
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow unnecessary calls to `.bind()`",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [],
 
        fixable: "code"
    },
 
    create(context) {
        let scopeInfo = null;
 
        /**
         * Reports a given function node.
         *
         * @param {ASTNode} node - A node to report. This is a FunctionExpression or
         *      an ArrowFunctionExpression.
         * @returns {void}
         */
        function report(node) {
            context.report({
                node: node.parent.parent,
                message: "The function binding is unnecessary.",
                loc: node.parent.property.loc.start,
                fix(fixer) {
                    const firstTokenToRemove = context.getSourceCode()
                        .getFirstTokenBetween(node.parent.object, node.parent.property, astUtils.isNotClosingParenToken);
 
                    return fixer.removeRange([firstTokenToRemove.range[0], node.parent.parent.range[1]]);
                }
            });
        }
 
        /**
         * Checks whether or not a given function node is the callee of `.bind()`
         * method.
         *
         * e.g. `(function() {}.bind(foo))`
         *
         * @param {ASTNode} node - A node to report. This is a FunctionExpression or
         *      an ArrowFunctionExpression.
         * @returns {boolean} `true` if the node is the callee of `.bind()` method.
         */
        function isCalleeOfBindMethod(node) {
            const parent = node.parent;
            const grandparent = parent.parent;
 
            return (
                grandparent &&
                grandparent.type === "CallExpression" &&
                grandparent.callee === parent &&
                grandparent.arguments.length === 1 &&
                parent.type === "MemberExpression" &&
                parent.object === node &&
                astUtils.getStaticPropertyName(parent) === "bind"
            );
        }
 
        /**
         * Adds a scope information object to the stack.
         *
         * @param {ASTNode} node - A node to add. This node is a FunctionExpression
         *      or a FunctionDeclaration node.
         * @returns {void}
         */
        function enterFunction(node) {
            scopeInfo = {
                isBound: isCalleeOfBindMethod(node),
                thisFound: false,
                upper: scopeInfo
            };
        }
 
        /**
         * Removes the scope information object from the top of the stack.
         * At the same time, this reports the function node if the function has
         * `.bind()` and the `this` keywords found.
         *
         * @param {ASTNode} node - A node to remove. This node is a
         *      FunctionExpression or a FunctionDeclaration node.
         * @returns {void}
         */
        function exitFunction(node) {
            if (scopeInfo.isBound && !scopeInfo.thisFound) {
                report(node);
            }
 
            scopeInfo = scopeInfo.upper;
        }
 
        /**
         * Reports a given arrow function if the function is callee of `.bind()`
         * method.
         *
         * @param {ASTNode} node - A node to report. This node is an
         *      ArrowFunctionExpression.
         * @returns {void}
         */
        function exitArrowFunction(node) {
            if (isCalleeOfBindMethod(node)) {
                report(node);
            }
        }
 
        /**
         * Set the mark as the `this` keyword was found in this scope.
         *
         * @returns {void}
         */
        function markAsThisFound() {
            if (scopeInfo) {
                scopeInfo.thisFound = true;
            }
        }
 
        return {
            "ArrowFunctionExpression:exit": exitArrowFunction,
            FunctionDeclaration: enterFunction,
            "FunctionDeclaration:exit": exitFunction,
            FunctionExpression: enterFunction,
            "FunctionExpression:exit": exitFunction,
            ThisExpression: markAsThisFound
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-extra-boolean-cast.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-extra-boolean-cast.js

Statements: 11.54% (3 / 26)      Branches: 0% (0 / 30)      Functions: 0% (0 / 4)      Lines: 11.54% (3 / 26)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124                      1           1                                                               1                                                                                                                                                    
/**
 * @fileoverview Rule to flag unnecessary double negation in Boolean contexts
 * @author Brandon Mills
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow unnecessary boolean casts",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: [],
 
        fixable: "code"
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        // Node types which have a test which will coerce values to booleans.
        const BOOLEAN_NODE_TYPES = [
            "IfStatement",
            "DoWhileStatement",
            "WhileStatement",
            "ConditionalExpression",
            "ForStatement"
        ];
 
        /**
         * Check if a node is in a context where its value would be coerced to a boolean at runtime.
         *
         * @param {Object} node The node
         * @param {Object} parent Its parent
         * @returns {boolean} If it is in a boolean context
         */
        function isInBooleanContext(node, parent) {
            return (
                (BOOLEAN_NODE_TYPES.indexOf(parent.type) !== -1 &&
                    node === parent.test) ||
 
                // !<bool>
                (parent.type === "UnaryExpression" &&
                    parent.operator === "!")
            );
        }
 
 
        return {
            UnaryExpression(node) {
                const ancestors = context.getAncestors(),
                    parent = ancestors.pop(),
                    grandparent = ancestors.pop();
 
                // Exit early if it's guaranteed not to match
                if (node.operator !== "!" ||
                        parent.type !== "UnaryExpression" ||
                        parent.operator !== "!") {
                    return;
                }
 
                if (isInBooleanContext(parent, grandparent) ||
 
                    // Boolean(<bool>) and new Boolean(<bool>)
                    ((grandparent.type === "CallExpression" || grandparent.type === "NewExpression") &&
                        grandparent.callee.type === "Identifier" &&
                        grandparent.callee.name === "Boolean")
                ) {
                    context.report({
                        node,
                        message: "Redundant double negation.",
                        fix: fixer => fixer.replaceText(parent, sourceCode.getText(node.argument))
                    });
                }
            },
            CallExpression(node) {
                const parent = node.parent;
 
                if (node.callee.type !== "Identifier" || node.callee.name !== "Boolean") {
                    return;
                }
 
                if (isInBooleanContext(node, parent)) {
                    context.report({
                        node,
                        message: "Redundant Boolean call.",
                        fix: fixer => {
                            if (!node.arguments.length) {
                                return fixer.replaceText(parent, "true");
                            }
 
                            if (node.arguments.length > 1 || node.arguments[0].type === "SpreadElement") {
                                return null;
                            }
 
                            const argument = node.arguments[0];
 
                            if (astUtils.getPrecedence(argument) < astUtils.getPrecedence(node.parent)) {
                                return fixer.replaceText(node, `(${sourceCode.getText(argument)})`);
                            }
                            return fixer.replaceText(node, sourceCode.getText(argument));
                        }
                    });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-extra-label.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-extra-label.js

Statements: 28% (7 / 25)      Branches: 0% (0 / 18)      Functions: 0% (0 / 6)      Lines: 28% (7 / 25)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142                      1           1                                             1                         1                         1                                     1                         1                                                                                      
/**
 * @fileoverview Rule to disallow unnecessary labels
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow unnecessary labels",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [],
 
        fixable: "code"
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
        let scopeInfo = null;
 
        /**
         * Creates a new scope with a breakable statement.
         *
         * @param {ASTNode} node - A node to create. This is a BreakableStatement.
         * @returns {void}
         */
        function enterBreakableStatement(node) {
            scopeInfo = {
                label: node.parent.type === "LabeledStatement" ? node.parent.label : null,
                breakable: true,
                upper: scopeInfo
            };
        }
 
        /**
         * Removes the top scope of the stack.
         *
         * @returns {void}
         */
        function exitBreakableStatement() {
            scopeInfo = scopeInfo.upper;
        }
 
        /**
         * Creates a new scope with a labeled statement.
         *
         * This ignores it if the body is a breakable statement.
         * In this case it's handled in the `enterBreakableStatement` function.
         *
         * @param {ASTNode} node - A node to create. This is a LabeledStatement.
         * @returns {void}
         */
        function enterLabeledStatement(node) {
            if (!astUtils.isBreakableStatement(node.body)) {
                scopeInfo = {
                    label: node.label,
                    breakable: false,
                    upper: scopeInfo
                };
            }
        }
 
        /**
         * Removes the top scope of the stack.
         *
         * This ignores it if the body is a breakable statement.
         * In this case it's handled in the `exitBreakableStatement` function.
         *
         * @param {ASTNode} node - A node. This is a LabeledStatement.
         * @returns {void}
         */
        function exitLabeledStatement(node) {
            if (!astUtils.isBreakableStatement(node.body)) {
                scopeInfo = scopeInfo.upper;
            }
        }
 
        /**
         * Reports a given control node if it's unnecessary.
         *
         * @param {ASTNode} node - A node. This is a BreakStatement or a
         *      ContinueStatement.
         * @returns {void}
         */
        function reportIfUnnecessary(node) {
            if (!node.label) {
                return;
            }
 
            const labelNode = node.label;
 
            for (let info = scopeInfo; info !== null; info = info.upper) {
                if (info.breakable || info.label && info.label.name === labelNode.name) {
                    if (info.breakable && info.label && info.label.name === labelNode.name) {
                        context.report({
                            node: labelNode,
                            message: "This label '{{name}}' is unnecessary.",
                            data: labelNode,
                            fix: fixer => fixer.removeRange([sourceCode.getFirstToken(node).range[1], labelNode.range[1]])
                        });
                    }
                    return;
                }
            }
        }
 
        return {
            WhileStatement: enterBreakableStatement,
            "WhileStatement:exit": exitBreakableStatement,
            DoWhileStatement: enterBreakableStatement,
            "DoWhileStatement:exit": exitBreakableStatement,
            ForStatement: enterBreakableStatement,
            "ForStatement:exit": exitBreakableStatement,
            ForInStatement: enterBreakableStatement,
            "ForInStatement:exit": exitBreakableStatement,
            ForOfStatement: enterBreakableStatement,
            "ForOfStatement:exit": exitBreakableStatement,
            SwitchStatement: enterBreakableStatement,
            "SwitchStatement:exit": exitBreakableStatement,
            LabeledStatement: enterLabeledStatement,
            "LabeledStatement:exit": exitLabeledStatement,
            BreakStatement: reportIfUnnecessary,
            ContinueStatement: reportIfUnnecessary
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-extra-parens.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-extra-parens.js

Statements: 10.55% (21 / 199)      Branches: 0% (0 / 289)      Functions: 0% (0 / 40)      Lines: 10.55% (21 / 199)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666                    1 1   1                                                                                                                                   1                                                                     1                             1                     1                   1                   1                                   1                         1                                       1                                           1                           1                                                                     1                                                         1                               1                                                           1                                           1                                         1                             1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
/**
 * @fileoverview Disallow parenthesising higher precedence subexpressions.
 * @author Michael Ficarra
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils.js");
const esUtils = require("esutils");
 
module.exports = {
    meta: {
        docs: {
            description: "disallow unnecessary parentheses",
            category: "Possible Errors",
            recommended: false
        },
 
        fixable: "code",
 
        schema: {
            anyOf: [
                {
                    type: "array",
                    items: [
                        {
                            enum: ["functions"]
                        }
                    ],
                    minItems: 0,
                    maxItems: 1
                },
                {
                    type: "array",
                    items: [
                        {
                            enum: ["all"]
                        },
                        {
                            type: "object",
                            properties: {
                                conditionalAssign: { type: "boolean" },
                                nestedBinaryExpressions: { type: "boolean" },
                                returnAssign: { type: "boolean" },
                                ignoreJSX: { enum: ["none", "all", "single-line", "multi-line"] }
                            },
                            additionalProperties: false
                        }
                    ],
                    minItems: 0,
                    maxItems: 2
                }
            ]
        }
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        const tokensToIgnore = new WeakSet();
        const isParenthesised = astUtils.isParenthesised.bind(astUtils, sourceCode);
        const precedence = astUtils.getPrecedence;
        const ALL_NODES = context.options[0] !== "functions";
        const EXCEPT_COND_ASSIGN = ALL_NODES && context.options[1] && context.options[1].conditionalAssign === false;
        const NESTED_BINARY = ALL_NODES && context.options[1] && context.options[1].nestedBinaryExpressions === false;
        const EXCEPT_RETURN_ASSIGN = ALL_NODES && context.options[1] && context.options[1].returnAssign === false;
        const IGNORE_JSX = ALL_NODES && context.options[1] && context.options[1].ignoreJSX;
        const PRECEDENCE_OF_ASSIGNMENT_EXPR = precedence({ type: "AssignmentExpression" });
        const PRECEDENCE_OF_UPDATE_EXPR = precedence({ type: "UpdateExpression" });
 
        /**
         * Determines if this rule should be enforced for a node given the current configuration.
         * @param {ASTNode} node - The node to be checked.
         * @returns {boolean} True if the rule should be enforced for this node.
         * @private
         */
        function ruleApplies(node) {
            if (node.type === "JSXElement") {
                const isSingleLine = node.loc.start.line === node.loc.end.line;
 
                switch (IGNORE_JSX) {
 
                    // Exclude this JSX element from linting
                    case "all":
                        return false;
 
                    // Exclude this JSX element if it is multi-line element
                    case "multi-line":
                        return isSingleLine;
 
                    // Exclude this JSX element if it is single-line element
                    case "single-line":
                        return !isSingleLine;
 
                    // Nothing special to be done for JSX elements
                    case "none":
                        break;
 
                    // no default
                }
            }
 
            return ALL_NODES || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression";
        }
 
        /**
         * Determines if a node is surrounded by parentheses twice.
         * @param {ASTNode} node - The node to be checked.
         * @returns {boolean} True if the node is doubly parenthesised.
         * @private
         */
        function isParenthesisedTwice(node) {
            const previousToken = sourceCode.getTokenBefore(node, 1),
                nextToken = sourceCode.getTokenAfter(node, 1);
 
            return isParenthesised(node) && previousToken && nextToken &&
                astUtils.isOpeningParenToken(previousToken) && previousToken.range[1] <= node.range[0] &&
                astUtils.isClosingParenToken(nextToken) && nextToken.range[0] >= node.range[1];
        }
 
        /**
         * Determines if a node is surrounded by (potentially) invalid parentheses.
         * @param {ASTNode} node - The node to be checked.
         * @returns {boolean} True if the node is incorrectly parenthesised.
         * @private
         */
        function hasExcessParens(node) {
            return ruleApplies(node) && isParenthesised(node);
        }
 
        /**
         * Determines if a node that is expected to be parenthesised is surrounded by
         * (potentially) invalid extra parentheses.
         * @param {ASTNode} node - The node to be checked.
         * @returns {boolean} True if the node is has an unexpected extra pair of parentheses.
         * @private
         */
        function hasDoubleExcessParens(node) {
            return ruleApplies(node) && isParenthesisedTwice(node);
        }
 
        /**
         * Determines if a node test expression is allowed to have a parenthesised assignment
         * @param {ASTNode} node - The node to be checked.
         * @returns {boolean} True if the assignment can be parenthesised.
         * @private
         */
        function isCondAssignException(node) {
            return EXCEPT_COND_ASSIGN && node.test.type === "AssignmentExpression";
        }
 
        /**
         * Determines if a node is in a return statement
         * @param {ASTNode} node - The node to be checked.
         * @returns {boolean} True if the node is in a return statement.
         * @private
         */
        function isInReturnStatement(node) {
            while (node) {
                if (node.type === "ReturnStatement" ||
                        (node.type === "ArrowFunctionExpression" && node.body.type !== "BlockStatement")) {
                    return true;
                }
                node = node.parent;
            }
 
            return false;
        }
 
        /**
         * Determines if a constructor function is newed-up with parens
         * @param {ASTNode} newExpression - The NewExpression node to be checked.
         * @returns {boolean} True if the constructor is called with parens.
         * @private
         */
        function isNewExpressionWithParens(newExpression) {
            const lastToken = sourceCode.getLastToken(newExpression);
            const penultimateToken = sourceCode.getTokenBefore(lastToken);
 
            return newExpression.arguments.length > 0 || astUtils.isOpeningParenToken(penultimateToken) && astUtils.isClosingParenToken(lastToken);
        }
 
        /**
         * Determines if a node is or contains an assignment expression
         * @param {ASTNode} node - The node to be checked.
         * @returns {boolean} True if the node is or contains an assignment expression.
         * @private
         */
        function containsAssignment(node) {
            if (node.type === "AssignmentExpression") {
                return true;
            } else if (node.type === "ConditionalExpression" &&
                    (node.consequent.type === "AssignmentExpression" || node.alternate.type === "AssignmentExpression")) {
                return true;
            } else if ((node.left && node.left.type === "AssignmentExpression") ||
                    (node.right && node.right.type === "AssignmentExpression")) {
                return true;
            }
 
            return false;
        }
 
        /**
         * Determines if a node is contained by or is itself a return statement and is allowed to have a parenthesised assignment
         * @param {ASTNode} node - The node to be checked.
         * @returns {boolean} True if the assignment can be parenthesised.
         * @private
         */
        function isReturnAssignException(node) {
            if (!EXCEPT_RETURN_ASSIGN || !isInReturnStatement(node)) {
                return false;
            }
 
            if (node.type === "ReturnStatement") {
                return node.argument && containsAssignment(node.argument);
            } else if (node.type === "ArrowFunctionExpression" && node.body.type !== "BlockStatement") {
                return containsAssignment(node.body);
            }
            return containsAssignment(node);
 
        }
 
        /**
         * Determines if a node following a [no LineTerminator here] restriction is
         * surrounded by (potentially) invalid extra parentheses.
         * @param {Token} token - The token preceding the [no LineTerminator here] restriction.
         * @param {ASTNode} node - The node to be checked.
         * @returns {boolean} True if the node is incorrectly parenthesised.
         * @private
         */
        function hasExcessParensNoLineTerminator(token, node) {
            if (token.loc.end.line === node.loc.start.line) {
                return hasExcessParens(node);
            }
 
            return hasDoubleExcessParens(node);
        }
 
        /**
         * Determines whether a node should be preceded by an additional space when removing parens
         * @param {ASTNode} node node to evaluate; must be surrounded by parentheses
         * @returns {boolean} `true` if a space should be inserted before the node
         * @private
         */
        function requiresLeadingSpace(node) {
            const leftParenToken = sourceCode.getTokenBefore(node);
            const tokenBeforeLeftParen = sourceCode.getTokenBefore(node, 1);
            const firstToken = sourceCode.getFirstToken(node);
 
            // If there is already whitespace before the previous token, don't add more.
            if (!tokenBeforeLeftParen || tokenBeforeLeftParen.end !== leftParenToken.start) {
                return false;
            }
 
            // If the parens are preceded by a keyword (e.g. `typeof(0)`), a space should be inserted (`typeof 0`)
            const precededByIdentiferPart = esUtils.code.isIdentifierPartES6(tokenBeforeLeftParen.value.slice(-1).charCodeAt(0));
 
            // However, a space should not be inserted unless the first character of the token is an identifier part
            // e.g. `typeof([])` should be fixed to `typeof[]`
            const startsWithIdentifierPart = esUtils.code.isIdentifierPartES6(firstToken.value.charCodeAt(0));
 
            // If the parens are preceded by and start with a unary plus/minus (e.g. `+(+foo)`), a space should be inserted (`+ +foo`)
            const precededByUnaryPlus = tokenBeforeLeftParen.type === "Punctuator" && tokenBeforeLeftParen.value === "+";
            const precededByUnaryMinus = tokenBeforeLeftParen.type === "Punctuator" && tokenBeforeLeftParen.value === "-";
 
            const startsWithUnaryPlus = firstToken.type === "Punctuator" && firstToken.value === "+";
            const startsWithUnaryMinus = firstToken.type === "Punctuator" && firstToken.value === "-";
 
            return (precededByIdentiferPart && startsWithIdentifierPart) ||
                (precededByUnaryPlus && startsWithUnaryPlus) ||
                (precededByUnaryMinus && startsWithUnaryMinus);
        }
 
        /**
         * Report the node
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function report(node) {
            const leftParenToken = sourceCode.getTokenBefore(node);
            const rightParenToken = sourceCode.getTokenAfter(node);
 
            if (tokensToIgnore.has(sourceCode.getFirstToken(node)) && !isParenthesisedTwice(node)) {
                return;
            }
 
            context.report({
                node,
                loc: leftParenToken.loc.start,
                message: "Gratuitous parentheses around expression.",
                fix(fixer) {
                    const parenthesizedSource = sourceCode.text.slice(leftParenToken.range[1], rightParenToken.range[0]);
 
                    return fixer.replaceTextRange([
                        leftParenToken.range[0],
                        rightParenToken.range[1]
                    ], (requiresLeadingSpace(node) ? " " : "") + parenthesizedSource);
                }
            });
        }
 
        /**
         * Evaluate Unary update
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function checkUnaryUpdate(node) {
            if (node.type === "UnaryExpression" && node.argument.type === "BinaryExpression" && node.argument.operator === "**") {
                return;
            }
 
            if (hasExcessParens(node.argument) && precedence(node.argument) >= precedence(node)) {
                report(node.argument);
            }
        }
 
        /**
         * Evaluate a new call
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function checkCallNew(node) {
            if (hasExcessParens(node.callee) && precedence(node.callee) >= precedence(node) && !(
                node.type === "CallExpression" &&
                (node.callee.type === "FunctionExpression" ||
                  node.callee.type === "NewExpression" && !isNewExpressionWithParens(node.callee)) &&
 
                // One set of parentheses are allowed for a function expression
                !hasDoubleExcessParens(node.callee)
            )) {
                report(node.callee);
            }
            if (node.arguments.length === 1) {
                if (hasDoubleExcessParens(node.arguments[0]) && precedence(node.arguments[0]) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
                    report(node.arguments[0]);
                }
            } else {
                [].forEach.call(node.arguments, arg => {
                    if (hasExcessParens(arg) && precedence(arg) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
                        report(arg);
                    }
                });
            }
        }
 
        /**
         * Evaluate binary logicals
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function checkBinaryLogical(node) {
            const prec = precedence(node);
            const leftPrecedence = precedence(node.left);
            const rightPrecedence = precedence(node.right);
            const isExponentiation = node.operator === "**";
            const shouldSkipLeft = (NESTED_BINARY && (node.left.type === "BinaryExpression" || node.left.type === "LogicalExpression")) ||
              node.left.type === "UnaryExpression" && isExponentiation;
            const shouldSkipRight = NESTED_BINARY && (node.right.type === "BinaryExpression" || node.right.type === "LogicalExpression");
 
            if (!shouldSkipLeft && hasExcessParens(node.left) && (leftPrecedence > prec || (leftPrecedence === prec && !isExponentiation))) {
                report(node.left);
            }
            if (!shouldSkipRight && hasExcessParens(node.right) && (rightPrecedence > prec || (rightPrecedence === prec && isExponentiation))) {
                report(node.right);
            }
        }
 
        /**
         * Check the parentheses around the super class of the given class definition.
         * @param {ASTNode} node The node of class declarations to check.
         * @returns {void}
         */
        function checkClass(node) {
            if (!node.superClass) {
                return;
            }
 
            // If `node.superClass` is a LeftHandSideExpression, parentheses are extra.
            // Otherwise, parentheses are needed.
            const hasExtraParens = precedence(node.superClass) > PRECEDENCE_OF_UPDATE_EXPR
                ? hasExcessParens(node.superClass)
                : hasDoubleExcessParens(node.superClass);
 
            if (hasExtraParens) {
                report(node.superClass);
            }
        }
 
        /**
         * Check the parentheses around the argument of the given spread operator.
         * @param {ASTNode} node The node of spread elements/properties to check.
         * @returns {void}
         */
        function checkSpreadOperator(node) {
            const hasExtraParens = precedence(node.argument) >= PRECEDENCE_OF_ASSIGNMENT_EXPR
                ? hasExcessParens(node.argument)
                : hasDoubleExcessParens(node.argument);
 
            if (hasExtraParens) {
                report(node.argument);
            }
        }
 
        /**
         * Checks the parentheses for an ExpressionStatement or ExportDefaultDeclaration
         * @param {ASTNode} node The ExpressionStatement.expression or ExportDefaultDeclaration.declaration node
         * @returns {void}
         */
        function checkExpressionOrExportStatement(node) {
            const firstToken = isParenthesised(node) ? sourceCode.getTokenBefore(node) : sourceCode.getFirstToken(node);
            const secondToken = sourceCode.getTokenAfter(firstToken, astUtils.isNotOpeningParenToken);
 
            if (
                astUtils.isOpeningParenToken(firstToken) &&
                (
                    astUtils.isOpeningBraceToken(secondToken) ||
                    secondToken.type === "Keyword" && (
                        secondToken.value === "function" ||
                        secondToken.value === "class" ||
                        secondToken.value === "let" && astUtils.isOpeningBracketToken(sourceCode.getTokenAfter(secondToken))
                    )
                )
            ) {
                tokensToIgnore.add(secondToken);
            }
 
            if (hasExcessParens(node)) {
                report(node);
            }
        }
 
        return {
            ArrayExpression(node) {
                [].forEach.call(node.elements, e => {
                    if (e && hasExcessParens(e) && precedence(e) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
                        report(e);
                    }
                });
            },
 
            ArrowFunctionExpression(node) {
                if (isReturnAssignException(node)) {
                    return;
                }
 
                if (node.body.type !== "BlockStatement") {
                    const firstBodyToken = sourceCode.getFirstToken(node.body, astUtils.isNotOpeningParenToken);
                    const tokenBeforeFirst = sourceCode.getTokenBefore(firstBodyToken);
 
                    if (astUtils.isOpeningParenToken(tokenBeforeFirst) && astUtils.isOpeningBraceToken(firstBodyToken)) {
                        tokensToIgnore.add(firstBodyToken);
                    }
                    if (hasExcessParens(node.body) && precedence(node.body) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
                        report(node.body);
                    }
                }
            },
 
            AssignmentExpression(node) {
                if (isReturnAssignException(node)) {
                    return;
                }
 
                if (hasExcessParens(node.right) && precedence(node.right) >= precedence(node)) {
                    report(node.right);
                }
            },
 
            BinaryExpression: checkBinaryLogical,
            CallExpression: checkCallNew,
 
            ConditionalExpression(node) {
                if (isReturnAssignException(node)) {
                    return;
                }
 
                if (hasExcessParens(node.test) && precedence(node.test) >= precedence({ type: "LogicalExpression", operator: "||" })) {
                    report(node.test);
                }
 
                if (hasExcessParens(node.consequent) && precedence(node.consequent) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
                    report(node.consequent);
                }
 
                if (hasExcessParens(node.alternate) && precedence(node.alternate) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
                    report(node.alternate);
                }
            },
 
            DoWhileStatement(node) {
                if (hasDoubleExcessParens(node.test) && !isCondAssignException(node)) {
                    report(node.test);
                }
            },
 
            ExportDefaultDeclaration: node => checkExpressionOrExportStatement(node.declaration),
            ExpressionStatement: node => checkExpressionOrExportStatement(node.expression),
 
            ForInStatement(node) {
                if (hasExcessParens(node.right)) {
                    report(node.right);
                }
            },
 
            ForOfStatement(node) {
                if (hasExcessParens(node.right)) {
                    report(node.right);
                }
            },
 
            ForStatement(node) {
                if (node.init && hasExcessParens(node.init)) {
                    report(node.init);
                }
 
                if (node.test && hasExcessParens(node.test) && !isCondAssignException(node)) {
                    report(node.test);
                }
 
                if (node.update && hasExcessParens(node.update)) {
                    report(node.update);
                }
            },
 
            IfStatement(node) {
                if (hasDoubleExcessParens(node.test) && !isCondAssignException(node)) {
                    report(node.test);
                }
            },
 
            LogicalExpression: checkBinaryLogical,
 
            MemberExpression(node) {
                if (
                    hasExcessParens(node.object) &&
                    precedence(node.object) >= precedence(node) &&
                    (
                        node.computed ||
                        !(
                            astUtils.isDecimalInteger(node.object) ||
 
                            // RegExp literal is allowed to have parens (#1589)
                            (node.object.type === "Literal" && node.object.regex)
                        )
                    )
                ) {
                    report(node.object);
                }
                if (node.computed && hasExcessParens(node.property)) {
                    report(node.property);
                }
            },
 
            NewExpression: checkCallNew,
 
            ObjectExpression(node) {
                [].forEach.call(node.properties, e => {
                    const v = e.value;
 
                    if (v && hasExcessParens(v) && precedence(v) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
                        report(v);
                    }
                });
            },
 
            ReturnStatement(node) {
                const returnToken = sourceCode.getFirstToken(node);
 
                if (isReturnAssignException(node)) {
                    return;
                }
 
                if (node.argument &&
                        hasExcessParensNoLineTerminator(returnToken, node.argument) &&
 
                        // RegExp literal is allowed to have parens (#1589)
                        !(node.argument.type === "Literal" && node.argument.regex)) {
                    report(node.argument);
                }
            },
 
            SequenceExpression(node) {
                [].forEach.call(node.expressions, e => {
                    if (hasExcessParens(e) && precedence(e) >= precedence(node)) {
                        report(e);
                    }
                });
            },
 
            SwitchCase(node) {
                if (node.test && hasExcessParens(node.test)) {
                    report(node.test);
                }
            },
 
            SwitchStatement(node) {
                if (hasDoubleExcessParens(node.discriminant)) {
                    report(node.discriminant);
                }
            },
 
            ThrowStatement(node) {
                const throwToken = sourceCode.getFirstToken(node);
 
                if (hasExcessParensNoLineTerminator(throwToken, node.argument)) {
                    report(node.argument);
                }
            },
 
            UnaryExpression: checkUnaryUpdate,
            UpdateExpression: checkUnaryUpdate,
            AwaitExpression: checkUnaryUpdate,
 
            VariableDeclarator(node) {
                if (node.init && hasExcessParens(node.init) &&
                        precedence(node.init) >= PRECEDENCE_OF_ASSIGNMENT_EXPR &&
 
                        // RegExp literal is allowed to have parens (#1589)
                        !(node.init.type === "Literal" && node.init.regex)) {
                    report(node.init);
                }
            },
 
            WhileStatement(node) {
                if (hasDoubleExcessParens(node.test) && !isCondAssignException(node)) {
                    report(node.test);
                }
            },
 
            WithStatement(node) {
                if (hasDoubleExcessParens(node.object)) {
                    report(node.object);
                }
            },
 
            YieldExpression(node) {
                if (node.argument) {
                    const yieldToken = sourceCode.getFirstToken(node);
 
                    if ((precedence(node.argument) >= precedence(node) &&
                            hasExcessParensNoLineTerminator(yieldToken, node.argument)) ||
                            hasDoubleExcessParens(node.argument)) {
                        report(node.argument);
                    }
                }
            },
 
            ClassDeclaration: checkClass,
            ClassExpression: checkClass,
 
            SpreadElement: checkSpreadOperator,
            SpreadProperty: checkSpreadOperator,
            ExperimentalSpreadProperty: checkSpreadOperator
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-extra-semi.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-extra-semi.js

Statements: 29.41% (5 / 17)      Branches: 0% (0 / 6)      Functions: 0% (0 / 7)      Lines: 29.41% (5 / 17)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120                      1 1           1                                       1                                             1                                                                                                                    
/**
 * @fileoverview Rule to flag use of unnecessary semicolons
 * @author Nicholas C. Zakas
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const FixTracker = require("../util/fix-tracker");
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow unnecessary semicolons",
            category: "Possible Errors",
            recommended: true
        },
 
        fixable: "code",
        schema: []
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        /**
         * Reports an unnecessary semicolon error.
         * @param {Node|Token} nodeOrToken - A node or a token to be reported.
         * @returns {void}
         */
        function report(nodeOrToken) {
            context.report({
                node: nodeOrToken,
                message: "Unnecessary semicolon.",
                fix(fixer) {
 
                    // Expand the replacement range to include the surrounding
                    // tokens to avoid conflicting with semi.
                    // https://github.com/eslint/eslint/issues/7928
                    return new FixTracker(fixer, context.getSourceCode())
                        .retainSurroundingTokens(nodeOrToken)
                        .remove(nodeOrToken);
                }
            });
        }
 
        /**
         * Checks for a part of a class body.
         * This checks tokens from a specified token to a next MethodDefinition or the end of class body.
         *
         * @param {Token} firstToken - The first token to check.
         * @returns {void}
         */
        function checkForPartOfClassBody(firstToken) {
            for (let token = firstToken;
                token.type === "Punctuator" && !astUtils.isClosingBraceToken(token);
                token = sourceCode.getTokenAfter(token)
            ) {
                if (astUtils.isSemicolonToken(token)) {
                    report(token);
                }
            }
        }
 
        return {
 
            /**
             * Reports this empty statement, except if the parent node is a loop.
             * @param {Node} node - A EmptyStatement node to be reported.
             * @returns {void}
             */
            EmptyStatement(node) {
                const parent = node.parent,
                    allowedParentTypes = [
                        "ForStatement",
                        "ForInStatement",
                        "ForOfStatement",
                        "WhileStatement",
                        "DoWhileStatement",
                        "IfStatement",
                        "LabeledStatement",
                        "WithStatement"
                    ];
 
                if (allowedParentTypes.indexOf(parent.type) === -1) {
                    report(node);
                }
            },
 
            /**
             * Checks tokens from the head of this class body to the first MethodDefinition or the end of this class body.
             * @param {Node} node - A ClassBody node to check.
             * @returns {void}
             */
            ClassBody(node) {
                checkForPartOfClassBody(sourceCode.getFirstToken(node, 1)); // 0 is `{`.
            },
 
            /**
             * Checks tokens from this MethodDefinition to the next MethodDefinition or the end of this class body.
             * @param {Node} node - A MethodDefinition node of the start point.
             * @returns {void}
             */
            MethodDefinition(node) {
                checkForPartOfClassBody(sourceCode.getTokenAfter(node));
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-fallthrough.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-fallthrough.js

Statements: 21.43% (6 / 28)      Branches: 0% (0 / 18)      Functions: 0% (0 / 8)      Lines: 21.43% (6 / 28)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137                    1           1                 1                       1                   1               1                                                                                                                                                                  
/**
 * @fileoverview Rule to flag fall-through cases in switch statements.
 * @author Matt DuVall <http://mattduvall.com/>
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const lodash = require("lodash");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const DEFAULT_FALLTHROUGH_COMMENT = /falls?\s?through/i;
 
/**
 * Checks whether or not a given node has a fallthrough comment.
 * @param {ASTNode} node - A SwitchCase node to get comments.
 * @param {RuleContext} context - A rule context which stores comments.
 * @param {RegExp} fallthroughCommentPattern - A pattern to match comment to.
 * @returns {boolean} `true` if the node has a valid fallthrough comment.
 */
function hasFallthroughComment(node, context, fallthroughCommentPattern) {
    const sourceCode = context.getSourceCode();
    const comment = lodash.last(sourceCode.getComments(node).leading);
 
    return Boolean(comment && fallthroughCommentPattern.test(comment.value));
}
 
/**
 * Checks whether or not a given code path segment is reachable.
 * @param {CodePathSegment} segment - A CodePathSegment to check.
 * @returns {boolean} `true` if the segment is reachable.
 */
function isReachable(segment) {
    return segment.reachable;
}
 
/**
 * Checks whether a node and a token are separated by blank lines
 * @param {ASTNode} node - The node to check
 * @param {Token} token - The token to compare against
 * @returns {boolean} `true` if there are blank lines between node and token
 */
function hasBlankLinesBetween(node, token) {
    return token.loc.start.line > node.loc.end.line + 1;
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow fallthrough of `case` statements",
            category: "Best Practices",
            recommended: true
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    commentPattern: {
                        type: "string"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const options = context.options[0] || {};
        let currentCodePath = null;
        const sourceCode = context.getSourceCode();
 
        /*
         * We need to use leading comments of the next SwitchCase node because
         * trailing comments is wrong if semicolons are omitted.
         */
        let fallthroughCase = null;
        let fallthroughCommentPattern = null;
 
        if (options.commentPattern) {
            fallthroughCommentPattern = new RegExp(options.commentPattern);
        } else {
            fallthroughCommentPattern = DEFAULT_FALLTHROUGH_COMMENT;
        }
 
        return {
            onCodePathStart(codePath) {
                currentCodePath = codePath;
            },
            onCodePathEnd() {
                currentCodePath = currentCodePath.upper;
            },
 
            SwitchCase(node) {
 
                /*
                 * Checks whether or not there is a fallthrough comment.
                 * And reports the previous fallthrough node if that does not exist.
                 */
                if (fallthroughCase && !hasFallthroughComment(node, context, fallthroughCommentPattern)) {
                    context.report({
                        message: "Expected a 'break' statement before '{{type}}'.",
                        data: { type: node.test ? "case" : "default" },
                        node
                    });
                }
                fallthroughCase = null;
            },
 
            "SwitchCase:exit"(node) {
                const nextToken = sourceCode.getTokenAfter(node);
 
                /*
                 * `reachable` meant fall through because statements preceded by
                 * `break`, `return`, or `throw` are unreachable.
                 * And allows empty cases and the last case.
                 */
                if (currentCodePath.currentSegments.some(isReachable) &&
                    (node.consequent.length > 0 || hasBlankLinesBetween(node, nextToken)) &&
                    lodash.last(node.parent.cases) !== node) {
                    fallthroughCase = node;
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-floating-decimal.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-floating-decimal.js

Statements: 11.11% (1 / 9)      Branches: 0% (0 / 6)      Functions: 0% (0 / 2)      Lines: 11.11% (1 / 9)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52                      1                                                                                
/**
 * @fileoverview Rule to flag use of a leading/trailing decimal point in a numeric literal
 * @author James Allardice
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow leading or trailing decimal points in numeric literals",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [],
 
        fixable: "code"
    },
 
    create(context) {
 
        return {
            Literal(node) {
 
                if (typeof node.value === "number") {
                    if (node.raw.indexOf(".") === 0) {
                        context.report({
                            node,
                            message: "A leading decimal point can be confused with a dot.",
                            fix: fixer => fixer.insertTextBefore(node, "0")
                        });
                    }
                    if (node.raw.indexOf(".") === node.raw.length - 1) {
                        context.report({
                            node,
                            message: "A trailing decimal point can be confused with a dot.",
                            fix: fixer => fixer.insertTextAfter(node, "0")
                        });
                    }
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-func-assign.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-func-assign.js

Statements: 45.45% (5 / 11)      Branches: 0% (0 / 2)      Functions: 0% (0 / 4)      Lines: 45.45% (5 / 11)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65              1           1                                   1                     1                     1                      
/**
 * @fileoverview Rule to flag use of function declaration identifiers as variables.
 * @author Ian Christian Myers
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow reassigning `function` declarations",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
 
        /**
         * Reports a reference if is non initializer and writable.
         * @param {References} references - Collection of reference to check.
         * @returns {void}
         */
        function checkReference(references) {
            astUtils.getModifyingReferences(references).forEach(reference => {
                context.report({ node: reference.identifier, message: "'{{name}}' is a function.", data: { name: reference.identifier.name } });
            });
        }
 
        /**
         * Finds and reports references that are non initializer and writable.
         * @param {Variable} variable - A variable to check.
         * @returns {void}
         */
        function checkVariable(variable) {
            if (variable.defs[0].type === "FunctionName") {
                checkReference(variable.references);
            }
        }
 
        /**
         * Checks parameters of a given function node.
         * @param {ASTNode} node - A function node to check.
         * @returns {void}
         */
        function checkForFunction(node) {
            context.getDeclaredVariables(node).forEach(checkVariable);
        }
 
        return {
            FunctionDeclaration: checkForFunction,
            FunctionExpression: checkForFunction
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-global-assign.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-global-assign.js

Statements: 23.08% (3 / 13)      Branches: 0% (0 / 13)      Functions: 0% (0 / 4)      Lines: 23.08% (3 / 13)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85                      1                                                                   1                                             1                                
/**
 * @fileoverview Rule to disallow assignments to native objects or read-only global variables
 * @author Ilya Volodin
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow assignments to native objects or read-only global variables",
            category: "Best Practices",
            recommended: true
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    exceptions: {
                        type: "array",
                        items: { type: "string" },
                        uniqueItems: true
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const config = context.options[0];
        const exceptions = (config && config.exceptions) || [];
 
        /**
         * Reports write references.
         * @param {Reference} reference - A reference to check.
         * @param {int} index - The index of the reference in the references.
         * @param {Reference[]} references - The array that the reference belongs to.
         * @returns {void}
         */
        function checkReference(reference, index, references) {
            const identifier = reference.identifier;
 
            if (reference.init === false &&
                reference.isWrite() &&
 
                // Destructuring assignments can have multiple default value,
                // so possibly there are multiple writeable references for the same identifier.
                (index === 0 || references[index - 1].identifier !== identifier)
            ) {
                context.report({
                    node: identifier,
                    message: "Read-only global '{{name}}' should not be modified.",
                    data: identifier
                });
            }
        }
 
        /**
         * Reports write references if a given variable is read-only builtin.
         * @param {Variable} variable - A variable to check.
         * @returns {void}
         */
        function checkVariable(variable) {
            if (variable.writeable === false && exceptions.indexOf(variable.name) === -1) {
                variable.references.forEach(checkReference);
            }
        }
 
        return {
            Program() {
                const globalScope = context.getScope();
 
                globalScope.variables.forEach(checkVariable);
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-implicit-coercion.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-implicit-coercion.js

Statements: 22.54% (16 / 71)      Branches: 0% (0 / 93)      Functions: 0% (0 / 16)      Lines: 22.54% (16 / 71)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296              1 1           1 1             1                             1                         1                             1                       1                                   1                                         1                 1                       1                 1               1                                                                                       1                                                                                                                                                                                                  
/**
 * @fileoverview A rule to disallow the type conversions with shorter notations.
 * @author Toru Nagashima
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
const esUtils = require("esutils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const INDEX_OF_PATTERN = /^(?:i|lastI)ndexOf$/;
const ALLOWABLE_OPERATORS = ["~", "!!", "+", "*"];
 
/**
 * Parses and normalizes an option object.
 * @param {Object} options - An option object to parse.
 * @returns {Object} The parsed and normalized option object.
 */
function parseOptions(options) {
    options = options || {};
    return {
        boolean: "boolean" in options ? Boolean(options.boolean) : true,
        number: "number" in options ? Boolean(options.number) : true,
        string: "string" in options ? Boolean(options.string) : true,
        allow: options.allow || []
    };
}
 
/**
 * Checks whether or not a node is a double logical nigating.
 * @param {ASTNode} node - An UnaryExpression node to check.
 * @returns {boolean} Whether or not the node is a double logical nigating.
 */
function isDoubleLogicalNegating(node) {
    return (
        node.operator === "!" &&
        node.argument.type === "UnaryExpression" &&
        node.argument.operator === "!"
    );
}
 
/**
 * Checks whether or not a node is a binary negating of `.indexOf()` method calling.
 * @param {ASTNode} node - An UnaryExpression node to check.
 * @returns {boolean} Whether or not the node is a binary negating of `.indexOf()` method calling.
 */
function isBinaryNegatingOfIndexOf(node) {
    return (
        node.operator === "~" &&
        node.argument.type === "CallExpression" &&
        node.argument.callee.type === "MemberExpression" &&
        node.argument.callee.property.type === "Identifier" &&
        INDEX_OF_PATTERN.test(node.argument.callee.property.name)
    );
}
 
/**
 * Checks whether or not a node is a multiplying by one.
 * @param {BinaryExpression} node - A BinaryExpression node to check.
 * @returns {boolean} Whether or not the node is a multiplying by one.
 */
function isMultiplyByOne(node) {
    return node.operator === "*" && (
        node.left.type === "Literal" && node.left.value === 1 ||
        node.right.type === "Literal" && node.right.value === 1
    );
}
 
/**
 * Checks whether the result of a node is numeric or not
 * @param {ASTNode} node The node to test
 * @returns {boolean} true if the node is a number literal or a `Number()`, `parseInt` or `parseFloat` call
 */
function isNumeric(node) {
    return (
        node.type === "Literal" && typeof node.value === "number" ||
        node.type === "CallExpression" && (
            node.callee.name === "Number" ||
            node.callee.name === "parseInt" ||
            node.callee.name === "parseFloat"
        )
    );
}
 
/**
 * Returns the first non-numeric operand in a BinaryExpression. Designed to be
 * used from bottom to up since it walks up the BinaryExpression trees using
 * node.parent to find the result.
 * @param {BinaryExpression} node The BinaryExpression node to be walked up on
 * @returns {ASTNode|null} The first non-numeric item in the BinaryExpression tree or null
 */
function getNonNumericOperand(node) {
    const left = node.left,
        right = node.right;
 
    if (right.type !== "BinaryExpression" && !isNumeric(right)) {
        return right;
    }
 
    if (left.type !== "BinaryExpression" && !isNumeric(left)) {
        return left;
    }
 
    return null;
}
 
/**
 * Checks whether a node is an empty string literal or not.
 * @param {ASTNode} node The node to check.
 * @returns {boolean} Whether or not the passed in node is an
 * empty string literal or not.
 */
function isEmptyString(node) {
    return astUtils.isStringLiteral(node) && (node.value === "" || (node.type === "TemplateLiteral" && node.quasis.length === 1 && node.quasis[0].value.cooked === ""));
}
 
/**
 * Checks whether or not a node is a concatenating with an empty string.
 * @param {ASTNode} node - A BinaryExpression node to check.
 * @returns {boolean} Whether or not the node is a concatenating with an empty string.
 */
function isConcatWithEmptyString(node) {
    return node.operator === "+" && (
        (isEmptyString(node.left) && !astUtils.isStringLiteral(node.right)) ||
        (isEmptyString(node.right) && !astUtils.isStringLiteral(node.left))
    );
}
 
/**
 * Checks whether or not a node is appended with an empty string.
 * @param {ASTNode} node - An AssignmentExpression node to check.
 * @returns {boolean} Whether or not the node is appended with an empty string.
 */
function isAppendEmptyString(node) {
    return node.operator === "+=" && isEmptyString(node.right);
}
 
/**
 * Returns the operand that is not an empty string from a flagged BinaryExpression.
 * @param {ASTNode} node - The flagged BinaryExpression node to check.
 * @returns {ASTNode} The operand that is not an empty string from a flagged BinaryExpression.
 */
function getNonEmptyOperand(node) {
    return isEmptyString(node.left) ? node.right : node.left;
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow shorthand type conversions",
            category: "Best Practices",
            recommended: false
        },
 
        fixable: "code",
        schema: [{
            type: "object",
            properties: {
                boolean: {
                    type: "boolean"
                },
                number: {
                    type: "boolean"
                },
                string: {
                    type: "boolean"
                },
                allow: {
                    type: "array",
                    items: {
                        enum: ALLOWABLE_OPERATORS
                    },
                    uniqueItems: true
                }
            },
            additionalProperties: false
        }]
    },
 
    create(context) {
        const options = parseOptions(context.options[0]);
        const sourceCode = context.getSourceCode();
 
        /**
        * Reports an error and autofixes the node
        * @param {ASTNode} node - An ast node to report the error on.
        * @param {string} recommendation - The recommended code for the issue
        * @param {bool} shouldFix - Whether this report should fix the node
        * @returns {void}
        */
        function report(node, recommendation, shouldFix) {
            shouldFix = typeof shouldFix === "undefined" ? true : shouldFix;
 
            context.report({
                node,
                message: "use `{{recommendation}}` instead.",
                data: {
                    recommendation
                },
                fix(fixer) {
                    if (!shouldFix) {
                        return null;
                    }
 
                    const tokenBefore = sourceCode.getTokenBefore(node);
 
                    if (
                        tokenBefore &&
                        tokenBefore.range[1] === node.range[0] &&
                        esUtils.code.isIdentifierPartES6(tokenBefore.value.slice(-1).charCodeAt(0)) &&
                        esUtils.code.isIdentifierPartES6(recommendation.charCodeAt(0))
                    ) {
                        return fixer.replaceText(node, ` ${recommendation}`);
                    }
                    return fixer.replaceText(node, recommendation);
                }
            });
        }
 
        return {
            UnaryExpression(node) {
                let operatorAllowed;
 
                // !!foo
                operatorAllowed = options.allow.indexOf("!!") >= 0;
                if (!operatorAllowed && options.boolean && isDoubleLogicalNegating(node)) {
                    const recommendation = `Boolean(${sourceCode.getText(node.argument.argument)})`;
 
                    report(node, recommendation);
                }
 
                // ~foo.indexOf(bar)
                operatorAllowed = options.allow.indexOf("~") >= 0;
                if (!operatorAllowed && options.boolean && isBinaryNegatingOfIndexOf(node)) {
                    const recommendation = `${sourceCode.getText(node.argument)} !== -1`;
 
                    report(node, recommendation, false);
                }
 
                // +foo
                operatorAllowed = options.allow.indexOf("+") >= 0;
                if (!operatorAllowed && options.number && node.operator === "+" && !isNumeric(node.argument)) {
                    const recommendation = `Number(${sourceCode.getText(node.argument)})`;
 
                    report(node, recommendation);
                }
            },
 
            // Use `:exit` to prevent double reporting
            "BinaryExpression:exit"(node) {
                let operatorAllowed;
 
                // 1 * foo
                operatorAllowed = options.allow.indexOf("*") >= 0;
                const nonNumericOperand = !operatorAllowed && options.number && isMultiplyByOne(node) && getNonNumericOperand(node);
 
                if (nonNumericOperand) {
                    const recommendation = `Number(${sourceCode.getText(nonNumericOperand)})`;
 
                    report(node, recommendation);
                }
 
                // "" + foo
                operatorAllowed = options.allow.indexOf("+") >= 0;
                if (!operatorAllowed && options.string && isConcatWithEmptyString(node)) {
                    const recommendation = `String(${sourceCode.getText(getNonEmptyOperand(node))})`;
 
                    report(node, recommendation);
                }
            },
 
            AssignmentExpression(node) {
 
                // foo += ""
                const operatorAllowed = options.allow.indexOf("+") >= 0;
 
                if (!operatorAllowed && options.string && isAppendEmptyString(node)) {
                    const code = sourceCode.getText(getNonEmptyOperand(node));
                    const recommendation = `${code} = String(${code})`;
 
                    report(node, recommendation);
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-implicit-globals.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-implicit-globals.js

Statements: 6.67% (1 / 15)      Branches: 0% (0 / 11)      Functions: 0% (0 / 2)      Lines: 6.67% (1 / 15)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57                      1                                                                                          
/**
 * @fileoverview Rule to check for implicit global variables and functions.
 * @author Joshua Peek
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow variable and `function` declarations in the global scope",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
        return {
            Program() {
                const scope = context.getScope();
 
                scope.variables.forEach(variable => {
                    if (variable.writeable) {
                        return;
                    }
 
                    variable.defs.forEach(def => {
                        if (def.type === "FunctionName" || (def.type === "Variable" && def.parent.kind === "var")) {
                            context.report({ node: def.node, message: "Implicit global variable, assign as global property instead." });
                        }
                    });
                });
 
                scope.implicit.variables.forEach(variable => {
                    const scopeVariable = scope.set.get(variable.name);
 
                    if (scopeVariable && scopeVariable.writeable) {
                        return;
                    }
 
                    variable.defs.forEach(def => {
                        context.report({ node: def.node, message: "Implicit global variable, assign as global property instead." });
                    });
                });
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-implied-eval.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-implied-eval.js

Statements: 20.69% (6 / 29)      Branches: 0% (0 / 29)      Functions: 0% (0 / 12)      Lines: 20.69% (6 / 29)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162                      1                                                           1                   1                                 1                               1                                 1                                                                                                                        
/**
 * @fileoverview Rule to flag use of implied eval via setTimeout and setInterval
 * @author James Allardice
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow the use of `eval()`-like methods",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
        const CALLEE_RE = /^(setTimeout|setInterval|execScript)$/;
 
        /*
         * Figures out if we should inspect a given binary expression. Is a stack
         * of stacks, where the first element in each substack is a CallExpression.
         */
        const impliedEvalAncestorsStack = [];
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Get the last element of an array, without modifying arr, like pop(), but non-destructive.
         * @param {array} arr What to inspect
         * @returns {*} The last element of arr
         * @private
         */
        function last(arr) {
            return arr ? arr[arr.length - 1] : null;
        }
 
        /**
         * Checks if the given MemberExpression node is a potentially implied eval identifier on window.
         * @param {ASTNode} node The MemberExpression node to check.
         * @returns {boolean} Whether or not the given node is potentially an implied eval.
         * @private
         */
        function isImpliedEvalMemberExpression(node) {
            const object = node.object,
                property = node.property,
                hasImpliedEvalName = CALLEE_RE.test(property.name) || CALLEE_RE.test(property.value);
 
            return object.name === "window" && hasImpliedEvalName;
        }
 
        /**
         * Determines if a node represents a call to a potentially implied eval.
         *
         * This checks the callee name and that there's an argument, but not the type of the argument.
         *
         * @param {ASTNode} node The CallExpression to check.
         * @returns {boolean} True if the node matches, false if not.
         * @private
         */
        function isImpliedEvalCallExpression(node) {
            const isMemberExpression = (node.callee.type === "MemberExpression"),
                isIdentifier = (node.callee.type === "Identifier"),
                isImpliedEvalCallee =
                    (isIdentifier && CALLEE_RE.test(node.callee.name)) ||
                    (isMemberExpression && isImpliedEvalMemberExpression(node.callee));
 
            return isImpliedEvalCallee && node.arguments.length;
        }
 
        /**
         * Checks that the parent is a direct descendent of an potential implied eval CallExpression, and if the parent is a CallExpression, that we're the first argument.
         * @param {ASTNode} node The node to inspect the parent of.
         * @returns {boolean} Was the parent a direct descendent, and is the child therefore potentially part of a dangerous argument?
         * @private
         */
        function hasImpliedEvalParent(node) {
 
            // make sure our parent is marked
            return node.parent === last(last(impliedEvalAncestorsStack)) &&
 
                // if our parent is a CallExpression, make sure we're the first argument
                (node.parent.type !== "CallExpression" || node === node.parent.arguments[0]);
        }
 
        /**
         * Checks if our parent is marked as part of an implied eval argument. If
         * so, collapses the top of impliedEvalAncestorsStack and reports on the
         * original CallExpression.
         * @param {ASTNode} node The CallExpression to check.
         * @returns {boolean} True if the node matches, false if not.
         * @private
         */
        function checkString(node) {
            if (hasImpliedEvalParent(node)) {
 
                // remove the entire substack, to avoid duplicate reports
                const substack = impliedEvalAncestorsStack.pop();
 
                context.report({ node: substack[0], message: "Implied eval. Consider passing a function instead of a string." });
            }
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            CallExpression(node) {
                if (isImpliedEvalCallExpression(node)) {
 
                    // call expressions create a new substack
                    impliedEvalAncestorsStack.push([node]);
                }
            },
 
            "CallExpression:exit"(node) {
                if (node === last(last(impliedEvalAncestorsStack))) {
 
                    /* Destroys the entire sub-stack, rather than just using
                     * last(impliedEvalAncestorsStack).pop(), as a CallExpression is
                     * always the bottom of a impliedEvalAncestorsStack substack.
                     */
                    impliedEvalAncestorsStack.pop();
                }
            },
 
            BinaryExpression(node) {
                if (node.operator === "+" && hasImpliedEvalParent(node)) {
                    last(impliedEvalAncestorsStack).push(node);
                }
            },
 
            "BinaryExpression:exit"(node) {
                if (node === last(last(impliedEvalAncestorsStack))) {
                    last(impliedEvalAncestorsStack).pop();
                }
            },
 
            Literal(node) {
                if (typeof node.value === "string") {
                    checkString(node);
                }
            },
 
            TemplateLiteral(node) {
                checkString(node);
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-inline-comments.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-inline-comments.js

Statements: 25% (3 / 12)      Branches: 0% (0 / 5)      Functions: 0% (0 / 2)      Lines: 25% (3 / 12)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66            1           1                                       1                                                                  
/**
 * @fileoverview Enforces or disallows inline comments.
 * @author Greg Cochard
 */
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow inline comments after code",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        /**
         * Will check that comments are not on lines starting with or ending with code
         * @param {ASTNode} node The comment node to check
         * @private
         * @returns {void}
         */
        function testCodeAroundComment(node) {
 
            // Get the whole line and cut it off at the start of the comment
            const startLine = String(sourceCode.lines[node.loc.start.line - 1]);
            const endLine = String(sourceCode.lines[node.loc.end.line - 1]);
 
            const preamble = startLine.slice(0, node.loc.start.column).trim();
 
            // Also check after the comment
            const postamble = endLine.slice(node.loc.end.column).trim();
 
            // Check that this comment isn't an ESLint directive
            const isDirective = astUtils.isDirectiveComment(node);
 
            // Should be empty if there was only whitespace around the comment
            if (!isDirective && (preamble || postamble)) {
                context.report({ node, message: "Unexpected comment inline with code." });
            }
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
 
            LineComment: testCodeAroundComment,
            BlockComment: testCodeAroundComment
 
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-inner-declarations.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-inner-declarations.js

Statements: 20% (3 / 15)      Branches: 0% (0 / 15)      Functions: 0% (0 / 4)      Lines: 20% (3 / 15)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89                      1                                         1                                                     1                                                          
/**
 * @fileoverview Rule to enforce declarations in program or function body root.
 * @author Brandon Mills
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow variable or `function` declarations in nested blocks",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: [
            {
                enum: ["functions", "both"]
            }
        ]
    },
 
    create(context) {
 
        /**
         * Find the nearest Program or Function ancestor node.
         * @returns {Object} Ancestor's type and distance from node.
         */
        function nearestBody() {
            const ancestors = context.getAncestors();
            let ancestor = ancestors.pop(),
                generation = 1;
 
            while (ancestor && ["Program", "FunctionDeclaration",
                "FunctionExpression", "ArrowFunctionExpression"
            ].indexOf(ancestor.type) < 0) {
                generation += 1;
                ancestor = ancestors.pop();
            }
 
            return {
 
                // Type of containing ancestor
                type: ancestor.type,
 
                // Separation between ancestor and node
                distance: generation
            };
        }
 
        /**
         * Ensure that a given node is at a program or function body's root.
         * @param {ASTNode} node Declaration node to check.
         * @returns {void}
         */
        function check(node) {
            const body = nearestBody(node),
                valid = ((body.type === "Program" && body.distance === 1) ||
                    body.distance === 2);
 
            if (!valid) {
                context.report({ node, message: "Move {{type}} declaration to {{body}} root.", data: {
                    type: (node.type === "FunctionDeclaration"
                            ? "function" : "variable"),
                    body: (body.type === "Program"
                            ? "program" : "function body")
                } });
            }
        }
 
        return {
 
            FunctionDeclaration: check,
            VariableDeclaration(node) {
                if (context.options[0] === "both" && node.kind === "var") {
                    check(node);
                }
            }
 
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-invalid-regexp.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-invalid-regexp.js

Statements: 19.05% (4 / 21)      Branches: 0% (0 / 18)      Functions: 0% (0 / 3)      Lines: 19.05% (4 / 21)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108                    1           1                                                                         1                   1                                                                                        
/**
 * @fileoverview Validate strings passed to the RegExp constructor
 * @author Michael Ficarra
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const espree = require("espree");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow invalid regular expression strings in `RegExp` constructors",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: [{
            type: "object",
            properties: {
                allowConstructorFlags: {
                    type: "array",
                    items: {
                        type: "string"
                    }
                }
            },
            additionalProperties: false
        }]
    },
 
    create(context) {
 
        const options = context.options[0];
        let allowedFlags = "";
 
        if (options && options.allowConstructorFlags) {
            allowedFlags = options.allowConstructorFlags.join("");
        }
 
        /**
         * Check if node is a string
         * @param {ASTNode} node node to evaluate
         * @returns {boolean} True if its a string
         * @private
         */
        function isString(node) {
            return node && node.type === "Literal" && typeof node.value === "string";
        }
 
        /**
         * Validate strings passed to the RegExp constructor
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function check(node) {
            if (node.callee.type === "Identifier" && node.callee.name === "RegExp" && isString(node.arguments[0])) {
                let flags = isString(node.arguments[1]) ? node.arguments[1].value : "";
 
                if (allowedFlags) {
                    flags = flags.replace(new RegExp(`[${allowedFlags}]`, "gi"), "");
                }
 
                try {
                    void new RegExp(node.arguments[0].value);
                } catch (e) {
                    context.report({
                        node,
                        message: "{{message}}.",
                        data: e
                    });
                }
 
                if (flags) {
 
                    try {
                        espree.parse(`/./${flags}`, context.parserOptions);
                    } catch (ex) {
                        context.report({
                            node,
                            message: "Invalid flags supplied to RegExp constructor '{{flags}}'.",
                            data: {
                                flags
                            }
                        });
                    }
                }
 
            }
        }
 
        return {
            CallExpression: check,
            NewExpression: check
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-invalid-this.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-invalid-this.js

Statements: 20% (4 / 20)      Branches: 0% (0 / 12)      Functions: 0% (0 / 7)      Lines: 20% (4 / 20)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124                      1           1                                                                                           1                           1                                                                                            
/**
 * @fileoverview A rule to disallow `this` keywords outside of classes or class-like objects.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `this` keywords outside of classes or class-like objects",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
        const stack = [],
            sourceCode = context.getSourceCode();
 
        /**
         * Gets the current checking context.
         *
         * The return value has a flag that whether or not `this` keyword is valid.
         * The flag is initialized when got at the first time.
         *
         * @returns {{valid: boolean}}
         *   an object which has a flag that whether or not `this` keyword is valid.
         */
        stack.getCurrent = function() {
            const current = this[this.length - 1];
 
            if (!current.init) {
                current.init = true;
                current.valid = !astUtils.isDefaultThisBinding(
                    current.node,
                    sourceCode);
            }
            return current;
        };
 
        /**
         * Pushs new checking context into the stack.
         *
         * The checking context is not initialized yet.
         * Because most functions don't have `this` keyword.
         * When `this` keyword was found, the checking context is initialized.
         *
         * @param {ASTNode} node - A function node that was entered.
         * @returns {void}
         */
        function enterFunction(node) {
 
            // `this` can be invalid only under strict mode.
            stack.push({
                init: !context.getScope().isStrict,
                node,
                valid: true
            });
        }
 
        /**
         * Pops the current checking context from the stack.
         * @returns {void}
         */
        function exitFunction() {
            stack.pop();
        }
 
        return {
 
            /*
             * `this` is invalid only under strict mode.
             * Modules is always strict mode.
             */
            Program(node) {
                const scope = context.getScope(),
                    features = context.parserOptions.ecmaFeatures || {};
 
                stack.push({
                    init: true,
                    node,
                    valid: !(
                        scope.isStrict ||
                        node.sourceType === "module" ||
                        (features.globalReturn && scope.childScopes[0].isStrict)
                    )
                });
            },
 
            "Program:exit"() {
                stack.pop();
            },
 
            FunctionDeclaration: enterFunction,
            "FunctionDeclaration:exit": exitFunction,
            FunctionExpression: enterFunction,
            "FunctionExpression:exit": exitFunction,
 
            // Reports if `this` of the current context is invalid.
            ThisExpression(node) {
                const current = stack.getCurrent();
 
                if (current && !current.valid) {
                    context.report({ node, message: "Unexpected 'this'." });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-irregular-whitespace.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-irregular-whitespace.js

Statements: 19.44% (14 / 72)      Branches: 0% (0 / 39)      Functions: 0% (0 / 11)      Lines: 19.44% (14 / 72)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254                        1           1 1 1 1           1                                                                                                         1                                           1                                     1                           1                       1                                               1                                                 1                 1                                                                                                
/**
 * @fileoverview Rule to disalow whitespace that is not a tab or space, whitespace inside strings and comments are allowed
 * @author Jonathan Kingston
 * @author Christophe Porteneuve
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Constants
//------------------------------------------------------------------------------
 
const ALL_IRREGULARS = /[\f\v\u0085\u00A0\ufeff\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u202f\u205f\u3000\u2028\u2029]/;
const IRREGULAR_WHITESPACE = /[\f\v\u0085\u00A0\ufeff\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u202f\u205f\u3000]+/mg;
const IRREGULAR_LINE_TERMINATORS = /[\u2028\u2029]/mg;
const LINE_BREAK = astUtils.createGlobalLinebreakMatcher();
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow irregular whitespace outside of strings and comments",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    skipComments: {
                        type: "boolean"
                    },
                    skipStrings: {
                        type: "boolean"
                    },
                    skipTemplates: {
                        type: "boolean"
                    },
                    skipRegExps: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        // Module store of errors that we have found
        let errors = [];
 
        // Comment nodes.  We accumulate these as we go, so we can be sure to trigger them after the whole `Program` entity is parsed, even for top-of-file comments.
        const commentNodes = [];
 
        // Lookup the `skipComments` option, which defaults to `false`.
        const options = context.options[0] || {};
        const skipComments = !!options.skipComments;
        const skipStrings = options.skipStrings !== false;
        const skipRegExps = !!options.skipRegExps;
        const skipTemplates = !!options.skipTemplates;
 
        const sourceCode = context.getSourceCode();
 
        /**
         * Removes errors that occur inside a string node
         * @param {ASTNode} node to check for matching errors.
         * @returns {void}
         * @private
         */
        function removeWhitespaceError(node) {
            const locStart = node.loc.start;
            const locEnd = node.loc.end;
 
            errors = errors.filter(error => {
                const errorLoc = error[1];
 
                if (errorLoc.line >= locStart.line && errorLoc.line <= locEnd.line) {
                    if (errorLoc.column >= locStart.column && (errorLoc.column <= locEnd.column || errorLoc.line < locEnd.line)) {
                        return false;
                    }
                }
                return true;
            });
        }
 
        /**
         * Checks identifier or literal nodes for errors that we are choosing to ignore and calls the relevant methods to remove the errors
         * @param {ASTNode} node to check for matching errors.
         * @returns {void}
         * @private
         */
        function removeInvalidNodeErrorsInIdentifierOrLiteral(node) {
            const shouldCheckStrings = skipStrings && (typeof node.value === "string");
            const shouldCheckRegExps = skipRegExps && (node.value instanceof RegExp);
 
            if (shouldCheckStrings || shouldCheckRegExps) {
 
                // If we have irregular characters remove them from the errors list
                if (ALL_IRREGULARS.test(node.raw)) {
                    removeWhitespaceError(node);
                }
            }
        }
 
        /**
         * Checks template string literal nodes for errors that we are choosing to ignore and calls the relevant methods to remove the errors
         * @param {ASTNode} node to check for matching errors.
         * @returns {void}
         * @private
         */
        function removeInvalidNodeErrorsInTemplateLiteral(node) {
            if (typeof node.value.raw === "string") {
                if (ALL_IRREGULARS.test(node.value.raw)) {
                    removeWhitespaceError(node);
                }
            }
        }
 
        /**
         * Checks comment nodes for errors that we are choosing to ignore and calls the relevant methods to remove the errors
         * @param {ASTNode} node to check for matching errors.
         * @returns {void}
         * @private
         */
        function removeInvalidNodeErrorsInComment(node) {
            if (ALL_IRREGULARS.test(node.value)) {
                removeWhitespaceError(node);
            }
        }
 
        /**
         * Checks the program source for irregular whitespace
         * @param {ASTNode} node The program node
         * @returns {void}
         * @private
         */
        function checkForIrregularWhitespace(node) {
            const sourceLines = sourceCode.lines;
 
            sourceLines.forEach((sourceLine, lineIndex) => {
                const lineNumber = lineIndex + 1;
                let match;
 
                while ((match = IRREGULAR_WHITESPACE.exec(sourceLine)) !== null) {
                    const location = {
                        line: lineNumber,
                        column: match.index
                    };
 
                    errors.push([node, location, "Irregular whitespace not allowed."]);
                }
            });
        }
 
        /**
         * Checks the program source for irregular line terminators
         * @param {ASTNode} node The program node
         * @returns {void}
         * @private
         */
        function checkForIrregularLineTerminators(node) {
            const source = sourceCode.getText(),
                sourceLines = sourceCode.lines,
                linebreaks = source.match(LINE_BREAK);
            let lastLineIndex = -1,
                match;
 
            while ((match = IRREGULAR_LINE_TERMINATORS.exec(source)) !== null) {
                const lineIndex = linebreaks.indexOf(match[0], lastLineIndex + 1) || 0;
                const location = {
                    line: lineIndex + 1,
                    column: sourceLines[lineIndex].length
                };
 
                errors.push([node, location, "Irregular whitespace not allowed."]);
                lastLineIndex = lineIndex;
            }
        }
 
        /**
         * Stores a comment node (`LineComment` or `BlockComment`) for later stripping of errors within; a necessary deferring of processing to deal with top-of-file comments.
         * @param {ASTNode} node The comment node
         * @returns {void}
         * @private
         */
        function rememberCommentNode(node) {
            commentNodes.push(node);
        }
 
        /**
         * A no-op function to act as placeholder for comment accumulation when the `skipComments` option is `false`.
         * @returns {void}
         * @private
         */
        function noop() {}
 
        const nodes = {};
 
        if (ALL_IRREGULARS.test(sourceCode.getText())) {
            nodes.Program = function(node) {
 
                /*
                 * As we can easily fire warnings for all white space issues with
                 * all the source its simpler to fire them here.
                 * This means we can check all the application code without having
                 * to worry about issues caused in the parser tokens.
                 * When writing this code also evaluating per node was missing out
                 * connecting tokens in some cases.
                 * We can later filter the errors when they are found to be not an
                 * issue in nodes we don't care about.
                 */
 
                checkForIrregularWhitespace(node);
                checkForIrregularLineTerminators(node);
            };
 
            nodes.Identifier = removeInvalidNodeErrorsInIdentifierOrLiteral;
            nodes.Literal = removeInvalidNodeErrorsInIdentifierOrLiteral;
            nodes.TemplateElement = skipTemplates ? removeInvalidNodeErrorsInTemplateLiteral : noop;
            nodes.LineComment = skipComments ? rememberCommentNode : noop;
            nodes.BlockComment = skipComments ? rememberCommentNode : noop;
            nodes["Program:exit"] = function() {
 
                if (skipComments) {
 
                    // First strip errors occurring in comment nodes.  We have to do this post-`Program` to deal with top-of-file comments.
                    commentNodes.forEach(removeInvalidNodeErrorsInComment);
                }
 
                // If we have any errors remaining report on them
                errors.forEach(error => {
                    context.report.apply(context, error);
                });
            };
        } else {
            nodes.Program = noop;
        }
 
        return nodes;
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-iterator.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-iterator.js

Statements: 25% (1 / 4)      Branches: 0% (0 / 8)      Functions: 0% (0 / 2)      Lines: 25% (1 / 4)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40                      1                                                        
/**
 * @fileoverview Rule to flag usage of __iterator__ property
 * @author Ian Christian Myers
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow the use of the `__iterator__` property",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
 
            MemberExpression(node) {
 
                if (node.property &&
                        (node.property.type === "Identifier" && node.property.name === "__iterator__" && !node.computed) ||
                        (node.property.type === "Literal" && node.property.value === "__iterator__")) {
                    context.report({ node, message: "Reserved name '__iterator__'." });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-label-var.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-label-var.js

Statements: 37.5% (3 / 8)      Branches: 0% (0 / 2)      Functions: 0% (0 / 3)      Lines: 37.5% (3 / 8)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69                      1           1                                               1                                                      
/**
 * @fileoverview Rule to flag labels that are the same as an identifier
 * @author Ian Christian Myers
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow labels that share a name with a variable",
            category: "Variables",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Check if the identifier is present inside current scope
         * @param {Object} scope current scope
         * @param {string} name To evaluate
         * @returns {boolean} True if its present
         * @private
         */
        function findIdentifier(scope, name) {
            return astUtils.getVariableByName(scope, name) !== null;
        }
 
        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------
 
        return {
 
            LabeledStatement(node) {
 
                // Fetch the innermost scope.
                const scope = context.getScope();
 
                // Recursively find the identifier walking up the scope, starting
                // with the innermost scope.
                if (findIdentifier(scope, node.label.name)) {
                    context.report({ node, message: "Found identifier with same name as label." });
                }
            }
 
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-labels.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-labels.js

Statements: 18.18% (6 / 33)      Branches: 0% (0 / 23)      Functions: 0% (0 / 8)      Lines: 18.18% (6 / 33)      Ignored: 1 statement     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143                    1           1                                                                       1                               1                           1                     1                                                                                                  
/**
 * @fileoverview Disallow Labeled Statements
 * @author Nicholas C. Zakas
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow labeled statements",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    allowLoop: {
                        type: "boolean"
                    },
                    allowSwitch: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const options = context.options[0];
        const allowLoop = Boolean(options && options.allowLoop);
        const allowSwitch = Boolean(options && options.allowSwitch);
        let scopeInfo = null;
 
        /**
         * Gets the kind of a given node.
         *
         * @param {ASTNode} node - A node to get.
         * @returns {string} The kind of the node.
         */
        function getBodyKind(node) {
            if (astUtils.isLoop(node)) {
                return "loop";
            }
            if (node.type === "SwitchStatement") {
                return "switch";
            }
            return "other";
        }
 
        /**
         * Checks whether the label of a given kind is allowed or not.
         *
         * @param {string} kind - A kind to check.
         * @returns {boolean} `true` if the kind is allowed.
         */
        function isAllowed(kind) {
            switch (kind) {
                case "loop": return allowLoop;
                case "switch": return allowSwitch;
                default: return false;
            }
        }
 
        /**
         * Checks whether a given name is a label of a loop or not.
         *
         * @param {string} label - A name of a label to check.
         * @returns {boolean} `true` if the name is a label of a loop.
         */
        function getKind(label) {
            let info = scopeInfo;
 
            while (info) {
                if (info.label === label) {
                    return info.kind;
                }
                info = info.upper;
            }
 
            /* istanbul ignore next: syntax error */
            return "other";
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            LabeledStatement(node) {
                scopeInfo = {
                    label: node.label.name,
                    kind: getBodyKind(node.body),
                    upper: scopeInfo
                };
            },
 
            "LabeledStatement:exit"(node) {
                if (!isAllowed(scopeInfo.kind)) {
                    context.report({
                        node,
                        message: "Unexpected labeled statement."
                    });
                }
 
                scopeInfo = scopeInfo.upper;
            },
 
            BreakStatement(node) {
                if (node.label && !isAllowed(getKind(node.label.name))) {
                    context.report({
                        node,
                        message: "Unexpected label in break statement."
                    });
                }
            },
 
            ContinueStatement(node) {
                if (node.label && !isAllowed(getKind(node.label.name))) {
                    context.report({
                        node,
                        message: "Unexpected label in continue statement."
                    });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-lone-blocks.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-lone-blocks.js

Statements: 12.5% (4 / 32)      Branches: 0% (0 / 28)      Functions: 0% (0 / 9)      Lines: 12.5% (4 / 32)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114                      1                                           1                     1                         1                                                                                                                
/**
 * @fileoverview Rule to flag blocks with no reason to exist
 * @author Brandon Mills
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow unnecessary nested blocks",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        // A stack of lone blocks to be checked for block-level bindings
        const loneBlocks = [];
        let ruleDef;
 
        /**
         * Reports a node as invalid.
         * @param {ASTNode} node - The node to be reported.
         * @returns {void}
        */
        function report(node) {
            const message = node.parent.type === "BlockStatement" ? "Nested block is redundant." : "Block is redundant.";
 
            context.report({ node, message });
        }
 
        /**
         * Checks for any ocurrence of a BlockStatement in a place where lists of statements can appear
         * @param {ASTNode} node The node to check
         * @returns {boolean} True if the node is a lone block.
        */
        function isLoneBlock(node) {
            return node.parent.type === "BlockStatement" ||
                node.parent.type === "Program" ||
 
                // Don't report blocks in switch cases if the block is the only statement of the case.
                node.parent.type === "SwitchCase" && !(node.parent.consequent[0] === node && node.parent.consequent.length === 1);
        }
 
        /**
         * Checks the enclosing block of the current node for block-level bindings,
         * and "marks it" as valid if any.
         * @returns {void}
        */
        function markLoneBlock() {
            if (loneBlocks.length === 0) {
                return;
            }
 
            const block = context.getAncestors().pop();
 
            if (loneBlocks[loneBlocks.length - 1] === block) {
                loneBlocks.pop();
            }
        }
 
        // Default rule definition: report all lone blocks
        ruleDef = {
            BlockStatement(node) {
                if (isLoneBlock(node)) {
                    report(node);
                }
            }
        };
 
        // ES6: report blocks without block-level bindings
        if (context.parserOptions.ecmaVersion >= 6) {
            ruleDef = {
                BlockStatement(node) {
                    if (isLoneBlock(node)) {
                        loneBlocks.push(node);
                    }
                },
                "BlockStatement:exit"(node) {
                    if (loneBlocks.length > 0 && loneBlocks[loneBlocks.length - 1] === node) {
                        loneBlocks.pop();
                        report(node);
                    }
                }
            };
 
            ruleDef.VariableDeclaration = function(node) {
                if (node.kind === "let" || node.kind === "const") {
                    markLoneBlock(node);
                }
            };
 
            ruleDef.FunctionDeclaration = function(node) {
                if (context.getScope().isStrict) {
                    markLoneBlock(node);
                }
            };
 
            ruleDef.ClassDeclaration = markLoneBlock;
        }
 
        return ruleDef;
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-lonely-if.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-lonely-if.js

Statements: 5.88% (1 / 17)      Branches: 0% (0 / 23)      Functions: 0% (0 / 3)      Lines: 5.88% (1 / 17)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84                    1                                                                                                                                                  
/**
 * @fileoverview Rule to disallow if as the only statmenet in an else block
 * @author Brandon Mills
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `if` statements as the only statement in `else` blocks",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [],
 
        fixable: "code"
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        return {
            IfStatement(node) {
                const ancestors = context.getAncestors(),
                    parent = ancestors.pop(),
                    grandparent = ancestors.pop();
 
                if (parent && parent.type === "BlockStatement" &&
                        parent.body.length === 1 && grandparent &&
                        grandparent.type === "IfStatement" &&
                        parent === grandparent.alternate) {
                    context.report({
                        node,
                        message: "Unexpected if as the only statement in an else block.",
                        fix(fixer) {
                            const openingElseCurly = sourceCode.getFirstToken(parent);
                            const closingElseCurly = sourceCode.getLastToken(parent);
                            const elseKeyword = sourceCode.getTokenBefore(openingElseCurly);
                            const tokenAfterElseBlock = sourceCode.getTokenAfter(closingElseCurly);
                            const lastIfToken = sourceCode.getLastToken(node.consequent);
                            const sourceText = sourceCode.getText();
 
                            if (sourceText.slice(openingElseCurly.range[1], node.range[0]).trim() || sourceText.slice(node.range[1], closingElseCurly.range[0]).trim()) {
 
                                // Don't fix if there are any non-whitespace characters interfering (e.g. comments)
                                return null;
                            }
 
                            if (
                                node.consequent.type !== "BlockStatement" && lastIfToken.value !== ";" && tokenAfterElseBlock &&
                                (
                                    node.consequent.loc.end.line === tokenAfterElseBlock.loc.start.line ||
                                    /^[([/+`-]/.test(tokenAfterElseBlock.value) ||
                                    lastIfToken.value === "++" ||
                                    lastIfToken.value === "--"
                                )
                            ) {
 
                                /*
                                 * If the `if` statement has no block, and is not followed by a semicolon, make sure that fixing
                                 * the issue would not change semantics due to ASI. If this would happen, don't do a fix.
                                 */
                                return null;
                            }
 
                            return fixer.replaceTextRange(
                                [openingElseCurly.range[0], closingElseCurly.range[1]],
                                (elseKeyword.range[1] === openingElseCurly.range[0] ? " " : "") + sourceCode.getText(node)
                            );
                        }
                    });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-loop-func.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-loop-func.js

Statements: 13.04% (6 / 46)      Branches: 0% (0 / 45)      Functions: 0% (0 / 6)      Lines: 13.04% (6 / 46)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200                                          1                                                                                                         1                                         1                                                                                 1                                 1                                           1                                                
/**
 * @fileoverview Rule to flag creation of function inside a loop
 * @author Ilya Volodin
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Gets the containing loop node of a specified node.
 *
 * We don't need to check nested functions, so this ignores those.
 * `Scope.through` contains references of nested functions.
 *
 * @param {ASTNode} node - An AST node to get.
 * @returns {ASTNode|null} The containing loop node of the specified node, or
 *      `null`.
 */
function getContainingLoopNode(node) {
    let parent = node.parent;
 
    while (parent) {
        switch (parent.type) {
            case "WhileStatement":
            case "DoWhileStatement":
                return parent;
 
            case "ForStatement":
 
                // `init` is outside of the loop.
                if (parent.init !== node) {
                    return parent;
                }
                break;
 
            case "ForInStatement":
            case "ForOfStatement":
 
                // `right` is outside of the loop.
                if (parent.right !== node) {
                    return parent;
                }
                break;
 
            case "ArrowFunctionExpression":
            case "FunctionExpression":
            case "FunctionDeclaration":
 
                // We don't need to check nested functions.
                return null;
 
            default:
                break;
        }
 
        node = parent;
        parent = node.parent;
    }
 
    return null;
}
 
/**
 * Gets the containing loop node of a given node.
 * If the loop was nested, this returns the most outer loop.
 *
 * @param {ASTNode} node - A node to get. This is a loop node.
 * @param {ASTNode|null} excludedNode - A node that the result node should not
 *      include.
 * @returns {ASTNode} The most outer loop node.
 */
function getTopLoopNode(node, excludedNode) {
    let retv = node;
    const border = excludedNode ? excludedNode.range[1] : 0;
 
    while (node && node.range[0] >= border) {
        retv = node;
        node = getContainingLoopNode(node);
    }
 
    return retv;
}
 
/**
 * Checks whether a given reference which refers to an upper scope's variable is
 * safe or not.
 *
 * @param {ASTNode} funcNode - A target function node.
 * @param {ASTNode} loopNode - A containing loop node.
 * @param {escope.Reference} reference - A reference to check.
 * @returns {boolean} `true` if the reference is safe or not.
 */
function isSafe(funcNode, loopNode, reference) {
    const variable = reference.resolved;
    const definition = variable && variable.defs[0];
    const declaration = definition && definition.parent;
    const kind = (declaration && declaration.type === "VariableDeclaration")
        ? declaration.kind
        : "";
 
    // Variables which are declared by `const` is safe.
    if (kind === "const") {
        return true;
    }
 
    // Variables which are declared by `let` in the loop is safe.
    // It's a different instance from the next loop step's.
    if (kind === "let" &&
        declaration.range[0] > loopNode.range[0] &&
        declaration.range[1] < loopNode.range[1]
    ) {
        return true;
    }
 
    // WriteReferences which exist after this border are unsafe because those
    // can modify the variable.
    const border = getTopLoopNode(
        loopNode,
        (kind === "let") ? declaration : null
    ).range[0];
 
    /**
     * Checks whether a given reference is safe or not.
     * The reference is every reference of the upper scope's variable we are
     * looking now.
     *
     * It's safeafe if the reference matches one of the following condition.
     * - is readonly.
     * - doesn't exist inside a local function and after the border.
     *
     * @param {escope.Reference} upperRef - A reference to check.
     * @returns {boolean} `true` if the reference is safe.
     */
    function isSafeReference(upperRef) {
        const id = upperRef.identifier;
 
        return (
            !upperRef.isWrite() ||
            variable.scope.variableScope === upperRef.from.variableScope &&
            id.range[0] < border
        );
    }
 
    return Boolean(variable) && variable.references.every(isSafeReference);
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `function` declarations and expressions inside loop statements",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        /**
         * Reports functions which match the following condition:
         *
         * - has a loop node in ancestors.
         * - has any references which refers to an unsafe variable.
         *
         * @param {ASTNode} node The AST node to check.
         * @returns {boolean} Whether or not the node is within a loop.
         */
        function checkForLoops(node) {
            const loopNode = getContainingLoopNode(node);
 
            if (!loopNode) {
                return;
            }
 
            const references = context.getScope().through;
 
            if (references.length > 0 &&
                !references.every(isSafe.bind(null, node, loopNode))
            ) {
                context.report({ node, message: "Don't make functions within a loop." });
            }
        }
 
        return {
            ArrowFunctionExpression: checkForLoops,
            FunctionExpression: checkForLoops,
            FunctionDeclaration: checkForLoops
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-magic-numbers.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-magic-numbers.js

Statements: 20.69% (6 / 29)      Branches: 0% (0 / 37)      Functions: 0% (0 / 7)      Lines: 20.69% (6 / 29)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151                      1                                                                                       1                 1                   1                         1                 1                                                                                                            
/**
 * @fileoverview Rule to flag statements that use magic numbers (adapted from https://github.com/danielstjules/buddy.js)
 * @author Vincent Lemeunier
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow magic numbers",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [{
            type: "object",
            properties: {
                detectObjects: {
                    type: "boolean"
                },
                enforceConst: {
                    type: "boolean"
                },
                ignore: {
                    type: "array",
                    items: {
                        type: "number"
                    },
                    uniqueItems: true
                },
                ignoreArrayIndexes: {
                    type: "boolean"
                }
            },
            additionalProperties: false
        }]
    },
 
    create(context) {
        const config = context.options[0] || {},
            detectObjects = !!config.detectObjects,
            enforceConst = !!config.enforceConst,
            ignore = config.ignore || [],
            ignoreArrayIndexes = !!config.ignoreArrayIndexes;
 
        /**
         * Returns whether the node is number literal
         * @param {Node} node - the node literal being evaluated
         * @returns {boolean} true if the node is a number literal
         */
        function isNumber(node) {
            return typeof node.value === "number";
        }
 
        /**
         * Returns whether the number should be ignored
         * @param {number} num - the number
         * @returns {boolean} true if the number should be ignored
         */
        function shouldIgnoreNumber(num) {
            return ignore.indexOf(num) !== -1;
        }
 
        /**
         * Returns whether the number should be ignored when used as a radix within parseInt() or Number.parseInt()
         * @param {ASTNode} parent - the non-"UnaryExpression" parent
         * @param {ASTNode} node - the node literal being evaluated
         * @returns {boolean} true if the number should be ignored
         */
        function shouldIgnoreParseInt(parent, node) {
            return parent.type === "CallExpression" && node === parent.arguments[1] &&
                (parent.callee.name === "parseInt" ||
                parent.callee.type === "MemberExpression" &&
                parent.callee.object.name === "Number" &&
                parent.callee.property.name === "parseInt");
        }
 
        /**
         * Returns whether the number should be ignored when used to define a JSX prop
         * @param {ASTNode} parent - the non-"UnaryExpression" parent
         * @returns {boolean} true if the number should be ignored
         */
        function shouldIgnoreJSXNumbers(parent) {
            return parent.type.indexOf("JSX") === 0;
        }
 
        /**
         * Returns whether the number should be ignored when used as an array index with enabled 'ignoreArrayIndexes' option.
         * @param {ASTNode} parent - the non-"UnaryExpression" parent.
         * @returns {boolean} true if the number should be ignored
         */
        function shouldIgnoreArrayIndexes(parent) {
            return parent.type === "MemberExpression" && ignoreArrayIndexes;
        }
 
        return {
            Literal(node) {
                let parent = node.parent,
                    value = node.value,
                    raw = node.raw;
                const okTypes = detectObjects ? [] : ["ObjectExpression", "Property", "AssignmentExpression"];
 
                if (!isNumber(node)) {
                    return;
                }
 
                // For negative magic numbers: update the value and parent node
                if (parent.type === "UnaryExpression" && parent.operator === "-") {
                    node = parent;
                    parent = node.parent;
                    value = -value;
                    raw = `-${raw}`;
                }
 
                if (shouldIgnoreNumber(value) ||
                    shouldIgnoreParseInt(parent, node) ||
                    shouldIgnoreArrayIndexes(parent) ||
                    shouldIgnoreJSXNumbers(parent)) {
                    return;
                }
 
                if (parent.type === "VariableDeclarator") {
                    if (enforceConst && parent.parent.kind !== "const") {
                        context.report({
                            node,
                            message: "Number constants declarations must use 'const'."
                        });
                    }
                } else if (
                    okTypes.indexOf(parent.type) === -1 ||
                    (parent.type === "AssignmentExpression" && parent.left.type === "Identifier")
                ) {
                    context.report({
                        node,
                        message: "No magic number: {{raw}}.",
                        data: {
                            raw
                        }
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-mixed-operators.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-mixed-operators.js

Statements: 42.5% (17 / 40)      Branches: 0% (0 / 23)      Functions: 0% (0 / 8)      Lines: 43.59% (17 / 39)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211                      1           1 1 1 1 1 1             1             1               1                                     1               1                                                                                   1                                           1                           1                         1                                                               1                                
/**
 * @fileoverview Rule to disallow mixed binary operators.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils.js");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const ARITHMETIC_OPERATORS = ["+", "-", "*", "/", "%", "**"];
const BITWISE_OPERATORS = ["&", "|", "^", "~", "<<", ">>", ">>>"];
const COMPARISON_OPERATORS = ["==", "!=", "===", "!==", ">", ">=", "<", "<="];
const LOGICAL_OPERATORS = ["&&", "||"];
const RELATIONAL_OPERATORS = ["in", "instanceof"];
const ALL_OPERATORS = [].concat(
    ARITHMETIC_OPERATORS,
    BITWISE_OPERATORS,
    COMPARISON_OPERATORS,
    LOGICAL_OPERATORS,
    RELATIONAL_OPERATORS
);
const DEFAULT_GROUPS = [
    ARITHMETIC_OPERATORS,
    BITWISE_OPERATORS,
    COMPARISON_OPERATORS,
    LOGICAL_OPERATORS,
    RELATIONAL_OPERATORS
];
const TARGET_NODE_TYPE = /^(?:Binary|Logical)Expression$/;
 
/**
 * Normalizes options.
 *
 * @param {Object|undefined} options - A options object to normalize.
 * @returns {Object} Normalized option object.
 */
function normalizeOptions(options) {
    const hasGroups = (options && options.groups && options.groups.length > 0);
    const groups = hasGroups ? options.groups : DEFAULT_GROUPS;
    const allowSamePrecedence = (options && options.allowSamePrecedence) !== false;
 
    return {
        groups,
        allowSamePrecedence
    };
}
 
/**
 * Checks whether any group which includes both given operator exists or not.
 *
 * @param {Array.<string[]>} groups - A list of groups to check.
 * @param {string} left - An operator.
 * @param {string} right - Another operator.
 * @returns {boolean} `true` if such group existed.
 */
function includesBothInAGroup(groups, left, right) {
    return groups.some(group => group.indexOf(left) !== -1 && group.indexOf(right) !== -1);
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow mixed binary operators",
            category: "Stylistic Issues",
            recommended: false
        },
        schema: [
            {
                type: "object",
                properties: {
                    groups: {
                        type: "array",
                        items: {
                            type: "array",
                            items: { enum: ALL_OPERATORS },
                            minItems: 2,
                            uniqueItems: true
                        },
                        uniqueItems: true
                    },
                    allowSamePrecedence: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
        const options = normalizeOptions(context.options[0]);
 
        /**
         * Checks whether a given node should be ignored by options or not.
         *
         * @param {ASTNode} node - A node to check. This is a BinaryExpression
         *      node or a LogicalExpression node. This parent node is one of
         *      them, too.
         * @returns {boolean} `true` if the node should be ignored.
         */
        function shouldIgnore(node) {
            const a = node;
            const b = node.parent;
 
            return (
                !includesBothInAGroup(options.groups, a.operator, b.operator) ||
                (
                    options.allowSamePrecedence &&
                    astUtils.getPrecedence(a) === astUtils.getPrecedence(b)
                )
            );
        }
 
        /**
         * Checks whether the operator of a given node is mixed with parent
         * node's operator or not.
         *
         * @param {ASTNode} node - A node to check. This is a BinaryExpression
         *      node or a LogicalExpression node. This parent node is one of
         *      them, too.
         * @returns {boolean} `true` if the node was mixed.
         */
        function isMixedWithParent(node) {
            return (
                node.operator !== node.parent.operator &&
                !astUtils.isParenthesised(sourceCode, node)
            );
        }
 
        /**
         * Gets the operator token of a given node.
         *
         * @param {ASTNode} node - A node to check. This is a BinaryExpression
         *      node or a LogicalExpression node.
         * @returns {Token} The operator token of the node.
         */
        function getOperatorToken(node) {
            return sourceCode.getTokenAfter(node.left, astUtils.isNotClosingParenToken);
        }
 
        /**
         * Reports both the operator of a given node and the operator of the
         * parent node.
         *
         * @param {ASTNode} node - A node to check. This is a BinaryExpression
         *      node or a LogicalExpression node. This parent node is one of
         *      them, too.
         * @returns {void}
         */
        function reportBothOperators(node) {
            const parent = node.parent;
            const left = (parent.left === node) ? node : parent;
            const right = (parent.left !== node) ? node : parent;
            const message =
                "Unexpected mix of '{{leftOperator}}' and '{{rightOperator}}'.";
            const data = {
                leftOperator: left.operator,
                rightOperator: right.operator
            };
 
            context.report({
                node: left,
                loc: getOperatorToken(left).loc.start,
                message,
                data
            });
            context.report({
                node: right,
                loc: getOperatorToken(right).loc.start,
                message,
                data
            });
        }
 
        /**
         * Checks between the operator of this node and the operator of the
         * parent node.
         *
         * @param {ASTNode} node - A node to check.
         * @returns {void}
         */
        function check(node) {
            if (TARGET_NODE_TYPE.test(node.parent.type) &&
                isMixedWithParent(node) &&
                !shouldIgnore(node)
            ) {
                reportBothOperators(node);
            }
        }
 
        return {
            BinaryExpression: check,
            LogicalExpression: check
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-mixed-requires.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-mixed-requires.js

Statements: 11.54% (6 / 52)      Branches: 0% (0 / 39)      Functions: 0% (0 / 7)      Lines: 11.54% (6 / 52)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218                      1                                                                                                 1                                                               1                                                                       1                                                                               1                                         1                                                        
/**
 * @fileoverview Rule to enforce grouped require statements for Node.JS
 * @author Raphael Pigulla
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `require` calls to be mixed with regular variable declarations",
            category: "Node.js and CommonJS",
            recommended: false
        },
 
        schema: [
            {
                oneOf: [
                    {
                        type: "boolean"
                    },
                    {
                        type: "object",
                        properties: {
                            grouping: {
                                type: "boolean"
                            },
                            allowCall: {
                                type: "boolean"
                            }
                        },
                        additionalProperties: false
                    }
                ]
            }
        ]
    },
 
    create(context) {
 
        const options = context.options[0];
        let grouping = false,
            allowCall = false;
 
        if (typeof options === "object") {
            grouping = options.grouping;
            allowCall = options.allowCall;
        } else {
            grouping = !!options;
        }
 
        /**
         * Returns the list of built-in modules.
         *
         * @returns {string[]} An array of built-in Node.js modules.
         */
        function getBuiltinModules() {
 
            /*
             * This list is generated using:
             * `require("repl")._builtinLibs.concat('repl').sort()`
             * This particular list is as per nodejs v0.12.2 and iojs v0.7.1
             */
            return [
                "assert", "buffer", "child_process", "cluster", "crypto",
                "dgram", "dns", "domain", "events", "fs", "http", "https",
                "net", "os", "path", "punycode", "querystring", "readline",
                "repl", "smalloc", "stream", "string_decoder", "tls", "tty",
                "url", "util", "v8", "vm", "zlib"
            ];
        }
 
        const BUILTIN_MODULES = getBuiltinModules();
 
        const DECL_REQUIRE = "require",
            DECL_UNINITIALIZED = "uninitialized",
            DECL_OTHER = "other";
 
        const REQ_CORE = "core",
            REQ_FILE = "file",
            REQ_MODULE = "module",
            REQ_COMPUTED = "computed";
 
        /**
         * Determines the type of a declaration statement.
         * @param {ASTNode} initExpression The init node of the VariableDeclarator.
         * @returns {string} The type of declaration represented by the expression.
         */
        function getDeclarationType(initExpression) {
            if (!initExpression) {
 
                // "var x;"
                return DECL_UNINITIALIZED;
            }
 
            if (initExpression.type === "CallExpression" &&
                initExpression.callee.type === "Identifier" &&
                initExpression.callee.name === "require"
            ) {
 
                // "var x = require('util');"
                return DECL_REQUIRE;
            } else if (allowCall &&
                initExpression.type === "CallExpression" &&
                initExpression.callee.type === "CallExpression"
            ) {
 
                // "var x = require('diagnose')('sub-module');"
                return getDeclarationType(initExpression.callee);
            } else if (initExpression.type === "MemberExpression") {
 
                // "var x = require('glob').Glob;"
                return getDeclarationType(initExpression.object);
            }
 
            // "var x = 42;"
            return DECL_OTHER;
        }
 
        /**
         * Determines the type of module that is loaded via require.
         * @param {ASTNode} initExpression The init node of the VariableDeclarator.
         * @returns {string} The module type.
         */
        function inferModuleType(initExpression) {
            if (initExpression.type === "MemberExpression") {
 
                // "var x = require('glob').Glob;"
                return inferModuleType(initExpression.object);
            } else if (initExpression.arguments.length === 0) {
 
                // "var x = require();"
                return REQ_COMPUTED;
            }
 
            const arg = initExpression.arguments[0];
 
            if (arg.type !== "Literal" || typeof arg.value !== "string") {
 
                // "var x = require(42);"
                return REQ_COMPUTED;
            }
 
            if (BUILTIN_MODULES.indexOf(arg.value) !== -1) {
 
                // "var fs = require('fs');"
                return REQ_CORE;
            } else if (/^\.{0,2}\//.test(arg.value)) {
 
                // "var utils = require('./utils');"
                return REQ_FILE;
            }
 
            // "var async = require('async');"
            return REQ_MODULE;
 
        }
 
        /**
         * Check if the list of variable declarations is mixed, i.e. whether it
         * contains both require and other declarations.
         * @param {ASTNode} declarations The list of VariableDeclarators.
         * @returns {boolean} True if the declarations are mixed, false if not.
         */
        function isMixed(declarations) {
            const contains = {};
 
            declarations.forEach(declaration => {
                const type = getDeclarationType(declaration.init);
 
                contains[type] = true;
            });
 
            return !!(
                contains[DECL_REQUIRE] &&
                (contains[DECL_UNINITIALIZED] || contains[DECL_OTHER])
            );
        }
 
        /**
         * Check if all require declarations in the given list are of the same
         * type.
         * @param {ASTNode} declarations The list of VariableDeclarators.
         * @returns {boolean} True if the declarations are grouped, false if not.
         */
        function isGrouped(declarations) {
            const found = {};
 
            declarations.forEach(declaration => {
                if (getDeclarationType(declaration.init) === DECL_REQUIRE) {
                    found[inferModuleType(declaration.init)] = true;
                }
            });
 
            return Object.keys(found).length <= 1;
        }
 
 
        return {
 
            VariableDeclaration(node) {
 
                if (isMixed(node.declarations)) {
                    context.report({ node, message: "Do not mix 'require' and other declarations." });
                } else if (grouping && !isGrouped(node.declarations)) {
                    context.report({ node, message: "Do not mix core, module, file and computed requires." });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-mixed-spaces-and-tabs.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-mixed-spaces-and-tabs.js

Statements: 7.32% (3 / 41)      Branches: 0% (0 / 23)      Functions: 0% (0 / 5)      Lines: 7.32% (3 / 41)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145                    1                                                                           1                             1                                                                                                                                                                  
/**
 * @fileoverview Disallow mixed spaces and tabs for indentation
 * @author Jary Niebur
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow mixed spaces and tabs for indentation",
            category: "Stylistic Issues",
            recommended: true
        },
 
        schema: [
            {
                enum: ["smart-tabs", true, false]
            }
        ]
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        let smartTabs;
        const ignoredLocs = [];
 
        switch (context.options[0]) {
            case true: // Support old syntax, maybe add deprecation warning here
            case "smart-tabs":
                smartTabs = true;
                break;
            default:
                smartTabs = false;
        }
 
        /**
         * Determines if a given line and column are before a location.
         * @param {Location} loc The location object from an AST node.
         * @param {int} line The line to check.
         * @param {int} column The column to check.
         * @returns {boolean} True if the line and column are before the location, false if not.
         * @private
         */
        function beforeLoc(loc, line, column) {
            if (line < loc.start.line) {
                return true;
            }
            return line === loc.start.line && column < loc.start.column;
        }
 
        /**
         * Determines if a given line and column are after a location.
         * @param {Location} loc The location object from an AST node.
         * @param {int} line The line to check.
         * @param {int} column The column to check.
         * @returns {boolean} True if the line and column are after the location, false if not.
         * @private
         */
        function afterLoc(loc, line, column) {
            if (line > loc.end.line) {
                return true;
            }
            return line === loc.end.line && column > loc.end.column;
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
 
            TemplateElement(node) {
                ignoredLocs.push(node.loc);
            },
 
            "Program:exit"(node) {
 
                /*
                 * At least one space followed by a tab
                 * or the reverse before non-tab/-space
                 * characters begin.
                 */
                let regex = /^(?=[\t ]*(\t | \t))/;
                const lines = sourceCode.lines,
                    comments = sourceCode.getAllComments();
 
                comments.forEach(comment => {
                    ignoredLocs.push(comment.loc);
                });
 
                ignoredLocs.sort((first, second) => {
                    if (beforeLoc(first, second.start.line, second.start.column)) {
                        return 1;
                    }
 
                    if (beforeLoc(second, first.start.line, second.start.column)) {
                        return -1;
                    }
 
                    return 0;
                });
 
                if (smartTabs) {
 
                    /*
                     * At least one space followed by a tab
                     * before non-tab/-space characters begin.
                     */
                    regex = /^(?=[\t ]* \t)/;
                }
 
                lines.forEach((line, i) => {
                    const match = regex.exec(line);
 
                    if (match) {
                        const lineNumber = i + 1,
                            column = match.index + 1;
 
                        for (let j = 0; j < ignoredLocs.length; j++) {
                            if (beforeLoc(ignoredLocs[j], lineNumber, column)) {
                                continue;
                            }
                            if (afterLoc(ignoredLocs[j], lineNumber, column)) {
                                continue;
                            }
 
                            return;
                        }
 
                        context.report({ node, loc: { line: lineNumber, column }, message: "Mixed spaces and tabs." });
                    }
                });
            }
 
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-multi-assign.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-multi-assign.js

Statements: 25% (1 / 4)      Branches: 0% (0 / 2)      Functions: 0% (0 / 2)      Lines: 25% (1 / 4)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43                        1                                                            
/**
 * @fileoverview Rule to check use of chained assignment expressions
 * @author Stewart Rand
 */
 
"use strict";
 
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow use of chained assignment expressions",
            category: "Stylistic Issues",
            recommended: false
        },
        schema: []
    },
 
    create(context) {
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            AssignmentExpression(node) {
                if (["AssignmentExpression", "VariableDeclarator"].indexOf(node.parent.type) !== -1) {
                    context.report({
                        node,
                        message: "Unexpected chained assignment."
                    });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-multi-spaces.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-multi-spaces.js

Statements: 11.76% (4 / 34)      Branches: 0% (0 / 22)      Functions: 0% (0 / 5)      Lines: 11.76% (4 / 34)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149              1           1                                                                                                                   1                                                                           1                                                                              
/**
 * @fileoverview Disallow use of multiple spaces.
 * @author Nicholas C. Zakas
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow multiple spaces",
            category: "Best Practices",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                type: "object",
                properties: {
                    exceptions: {
                        type: "object",
                        patternProperties: {
                            "^([A-Z][a-z]*)+$": {
                                type: "boolean"
                            }
                        },
                        additionalProperties: false
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        // the index of the last comment that was checked
        const exceptions = { Property: true },
            options = context.options[0];
        let hasExceptions = true,
            lastCommentIndex = 0;
 
        if (options && options.exceptions) {
            Object.keys(options.exceptions).forEach(key => {
                if (options.exceptions[key]) {
                    exceptions[key] = true;
                } else {
                    delete exceptions[key];
                }
            });
            hasExceptions = Object.keys(exceptions).length > 0;
        }
 
        /**
         * Determines if a given source index is in a comment or not by checking
         * the index against the comment range. Since the check goes straight
         * through the file, once an index is passed a certain comment, we can
         * go to the next comment to check that.
         * @param {int} index The source index to check.
         * @param {ASTNode[]} comments An array of comment nodes.
         * @returns {boolean} True if the index is within a comment, false if not.
         * @private
         */
        function isIndexInComment(index, comments) {
            while (lastCommentIndex < comments.length) {
                const comment = comments[lastCommentIndex];
 
                if (comment.range[0] <= index && index < comment.range[1]) {
                    return true;
                } else if (index > comment.range[1]) {
                    lastCommentIndex++;
                } else {
                    break;
                }
            }
 
            return false;
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            Program() {
 
                const sourceCode = context.getSourceCode(),
                    source = sourceCode.getText(),
                    allComments = sourceCode.getAllComments(),
                    JOINED_LINEBEAKS = Array.from(astUtils.LINEBREAKS).join(""),
                    pattern = new RegExp(String.raw`[^ \t${JOINED_LINEBEAKS}].? {2,}`, "g");  // note: repeating space
                let parent;
 
 
                /**
                 * Creates a fix function that removes the multiple spaces between the two tokens
                 * @param {RuleFixer} leftToken left token
                 * @param {RuleFixer} rightToken right token
                 * @returns {Function} fix function
                 * @private
                 */
                function createFix(leftToken, rightToken) {
                    return function(fixer) {
                        return fixer.replaceTextRange([leftToken.range[1], rightToken.range[0]], " ");
                    };
                }
 
                while (pattern.test(source)) {
 
                    // do not flag anything inside of comments
                    if (!isIndexInComment(pattern.lastIndex, allComments)) {
 
                        const token = sourceCode.getTokenByRangeStart(pattern.lastIndex);
 
                        if (token) {
                            const previousToken = sourceCode.getTokenBefore(token);
 
                            if (hasExceptions) {
                                parent = sourceCode.getNodeByRangeIndex(pattern.lastIndex - 1);
                            }
 
                            if (!parent || !exceptions[parent.type]) {
                                context.report({
                                    node: token,
                                    loc: token.loc.start,
                                    message: "Multiple spaces found before '{{value}}'.",
                                    data: { value: token.value },
                                    fix: createFix(previousToken, token)
                                });
                            }
                        }
 
                    }
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-multi-str.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-multi-str.js

Statements: 42.86% (3 / 7)      Branches: 0% (0 / 4)      Functions: 0% (0 / 3)      Lines: 42.86% (3 / 7)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57                      1           1                                     1                                        
/**
 * @fileoverview Rule to flag when using multiline strings
 * @author Ilya Volodin
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow multiline strings",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        /**
         * Determines if a given node is part of JSX syntax.
         * @param {ASTNode} node The node to check.
         * @returns {boolean} True if the node is a JSX node, false if not.
         * @private
         */
        function isJSXElement(node) {
            return node.type.indexOf("JSX") === 0;
        }
 
        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------
 
        return {
 
            Literal(node) {
                if (astUtils.LINEBREAK_MATCHER.test(node.raw) && !isJSXElement(node.parent)) {
                    context.report({ node, message: "Multiline support is limited to browsers supporting ES5 only." });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-multiple-empty-lines.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-multiple-empty-lines.js

Statements: 3.33% (1 / 30)      Branches: 0% (0 / 20)      Functions: 0% (0 / 4)      Lines: 3.33% (1 / 30)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129                      1                                                                                                                                                                                                                                          
/**
 * @fileoverview Disallows multiple blank lines.
 * implementation adapted from the no-trailing-spaces rule.
 * @author Greg Cochard
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow multiple empty lines",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                type: "object",
                properties: {
                    max: {
                        type: "integer",
                        minimum: 0
                    },
                    maxEOF: {
                        type: "integer",
                        minimum: 0
                    },
                    maxBOF: {
                        type: "integer",
                        minimum: 0
                    }
                },
                required: ["max"],
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        // Use options.max or 2 as default
        let max = 2,
            maxEOF = max,
            maxBOF = max;
 
        if (context.options.length) {
            max = context.options[0].max;
            maxEOF = typeof context.options[0].maxEOF !== "undefined" ? context.options[0].maxEOF : max;
            maxBOF = typeof context.options[0].maxBOF !== "undefined" ? context.options[0].maxBOF : max;
        }
 
        const sourceCode = context.getSourceCode();
 
        // Swallow the final newline, as some editors add it automatically and we don't want it to cause an issue
        const allLines = sourceCode.lines[sourceCode.lines.length - 1] === "" ? sourceCode.lines.slice(0, -1) : sourceCode.lines;
        const templateLiteralLines = new Set();
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            TemplateLiteral(node) {
                node.quasis.forEach(literalPart => {
 
                    // Empty lines have a semantic meaning if they're inside template literals. Don't count these as empty lines.
                    for (let ignoredLine = literalPart.loc.start.line; ignoredLine < literalPart.loc.end.line; ignoredLine++) {
                        templateLiteralLines.add(ignoredLine);
                    }
                });
            },
            "Program:exit"(node) {
                return allLines
 
                    // Given a list of lines, first get a list of line numbers that are non-empty.
                    .reduce((nonEmptyLineNumbers, line, index) => {
                        if (line.trim() || templateLiteralLines.has(index + 1)) {
                            nonEmptyLineNumbers.push(index + 1);
                        }
                        return nonEmptyLineNumbers;
                    }, [])
 
                    // Add a value at the end to allow trailing empty lines to be checked.
                    .concat(allLines.length + 1)
 
                    // Given two line numbers of non-empty lines, report the lines between if the difference is too large.
                    .reduce((lastLineNumber, lineNumber) => {
                        let message, maxAllowed;
 
                        if (lastLineNumber === 0) {
                            message = "Too many blank lines at the beginning of file. Max of {{max}} allowed.";
                            maxAllowed = maxBOF;
                        } else if (lineNumber === allLines.length + 1) {
                            message = "Too many blank lines at the end of file. Max of {{max}} allowed.";
                            maxAllowed = maxEOF;
                        } else {
                            message = "More than {{max}} blank {{pluralizedLines}} not allowed.";
                            maxAllowed = max;
                        }
 
                        if (lineNumber - lastLineNumber - 1 > maxAllowed) {
                            context.report({
                                node,
                                loc: { start: { line: lastLineNumber + 1, column: 0 }, end: { line: lineNumber, column: 0 } },
                                message,
                                data: { max: maxAllowed, pluralizedLines: maxAllowed === 1 ? "line" : "lines" },
                                fix(fixer) {
                                    return fixer.removeRange([
                                        sourceCode.getIndexFromLoc({ line: lastLineNumber + 1, column: 0 }),
                                        sourceCode.getIndexFromLoc({ line: lineNumber - maxAllowed, column: 0 })
                                    ]);
                                }
                            });
                        }
 
                        return lineNumber;
                    }, 0);
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-native-reassign.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-native-reassign.js

Statements: 23.08% (3 / 13)      Branches: 0% (0 / 13)      Functions: 0% (0 / 4)      Lines: 23.08% (3 / 13)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89                        1                                                                         1                                             1                                
/**
 * @fileoverview Rule to disallow assignments to native objects or read-only global variables
 * @author Ilya Volodin
 * @deprecated in ESLint v3.3.0
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow assignments to native objects or read-only global variables",
            category: "Best Practices",
            recommended: false,
            replacedBy: ["no-global-assign"]
        },
 
        deprecated: true,
 
        schema: [
            {
                type: "object",
                properties: {
                    exceptions: {
                        type: "array",
                        items: { type: "string" },
                        uniqueItems: true
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const config = context.options[0];
        const exceptions = (config && config.exceptions) || [];
 
        /**
         * Reports write references.
         * @param {Reference} reference - A reference to check.
         * @param {int} index - The index of the reference in the references.
         * @param {Reference[]} references - The array that the reference belongs to.
         * @returns {void}
         */
        function checkReference(reference, index, references) {
            const identifier = reference.identifier;
 
            if (reference.init === false &&
                reference.isWrite() &&
 
                // Destructuring assignments can have multiple default value,
                // so possibly there are multiple writeable references for the same identifier.
                (index === 0 || references[index - 1].identifier !== identifier)
            ) {
                context.report({
                    node: identifier,
                    message: "Read-only global '{{name}}' should not be modified.",
                    data: identifier
                });
            }
        }
 
        /**
         * Reports write references if a given variable is read-only builtin.
         * @param {Variable} variable - A variable to check.
         * @returns {void}
         */
        function checkVariable(variable) {
            if (variable.writeable === false && exceptions.indexOf(variable.name) === -1) {
                variable.references.forEach(checkReference);
            }
        }
 
        return {
            Program() {
                const globalScope = context.getScope();
 
                globalScope.variables.forEach(checkVariable);
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-negated-condition.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-negated-condition.js

Statements: 31.25% (5 / 16)      Branches: 0% (0 / 15)      Functions: 0% (0 / 7)      Lines: 31.25% (5 / 16)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84                    1                                     1                   1                   1                     1                                              
/**
 * @fileoverview Rule to disallow a negated condition
 * @author Alberto Rodríguez
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow negated conditions",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        /**
         * Determines if a given node is an if-else without a condition on the else
         * @param {ASTNode} node The node to check.
         * @returns {boolean} True if the node has an else without an if.
         * @private
         */
        function hasElseWithoutCondition(node) {
            return node.alternate && node.alternate.type !== "IfStatement";
        }
 
        /**
         * Determines if a given node is a negated unary expression
         * @param {Object} test The test object to check.
         * @returns {boolean} True if the node is a negated unary expression.
         * @private
         */
        function isNegatedUnaryExpression(test) {
            return test.type === "UnaryExpression" && test.operator === "!";
        }
 
        /**
         * Determines if a given node is a negated binary expression
         * @param {Test} test The test to check.
         * @returns {boolean} True if the node is a negated binary expression.
         * @private
         */
        function isNegatedBinaryExpression(test) {
            return test.type === "BinaryExpression" &&
                (test.operator === "!=" || test.operator === "!==");
        }
 
        /**
         * Determines if a given node has a negated if expression
         * @param {ASTNode} node The node to check.
         * @returns {boolean} True if the node has a negated if expression.
         * @private
         */
        function isNegatedIf(node) {
            return isNegatedUnaryExpression(node.test) || isNegatedBinaryExpression(node.test);
        }
 
        return {
            IfStatement(node) {
                if (!hasElseWithoutCondition(node)) {
                    return;
                }
 
                if (isNegatedIf(node)) {
                    context.report({ node, message: "Unexpected negated condition." });
                }
            },
            ConditionalExpression(node) {
                if (isNegatedIf(node)) {
                    context.report({ node, message: "Unexpected negated condition." });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-negated-in-lhs.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-negated-in-lhs.js

Statements: 25% (1 / 4)      Branches: 0% (0 / 5)      Functions: 0% (0 / 2)      Lines: 25% (1 / 4)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40                        1                                                      
/**
 * @fileoverview A rule to disallow negated left operands of the `in` operator
 * @author Michael Ficarra
 * @deprecated in ESLint v3.3.0
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow negating the left operand in `in` expressions",
            category: "Possible Errors",
            recommended: false,
            replacedBy: ["no-unsafe-negation"]
        },
        deprecated: true,
 
        schema: []
    },
 
    create(context) {
 
        return {
 
            BinaryExpression(node) {
                if (node.operator === "in" && node.left.type === "UnaryExpression" && node.left.operator === "!") {
                    context.report({ node, message: "The 'in' expression's left operand is negated." });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-nested-ternary.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-nested-ternary.js

Statements: 25% (1 / 4)      Branches: 0% (0 / 4)      Functions: 0% (0 / 2)      Lines: 25% (1 / 4)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36                      1                                                
/**
 * @fileoverview Rule to flag nested ternary expressions
 * @author Ian Christian Myers
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow nested ternary expressions",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
            ConditionalExpression(node) {
                if (node.alternate.type === "ConditionalExpression" ||
                        node.consequent.type === "ConditionalExpression") {
                    context.report({ node, message: "Do not nest ternary expressions." });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-new-func.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-new-func.js

Statements: 50% (2 / 4)      Branches: 100% (0 / 0)      Functions: 0% (0 / 2)      Lines: 50% (2 / 4)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47                      1                                             1                        
/**
 * @fileoverview Rule to flag when using new Function
 * @author Ilya Volodin
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `new` operators with the `Function` object",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Reports a node.
         * @param {ASTNode} node The node to report
         * @returns {void}
         * @private
         */
        function report(node) {
            context.report({ node, message: "The Function constructor is eval." });
        }
 
        return {
            "NewExpression[callee.name = 'Function']": report,
            "CallExpression[callee.name = 'Function']": report
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-new-object.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-new-object.js

Statements: 25% (1 / 4)      Branches: 0% (0 / 2)      Functions: 0% (0 / 2)      Lines: 25% (1 / 4)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37                      1                                                  
/**
 * @fileoverview A rule to disallow calls to the Object constructor
 * @author Matt DuVall <http://www.mattduvall.com/>
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `Object` constructors",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
 
            NewExpression(node) {
                if (node.callee.name === "Object") {
                    context.report({ node, message: "The object literal notation {} is preferrable." });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-new-require.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-new-require.js

Statements: 25% (1 / 4)      Branches: 0% (0 / 4)      Functions: 0% (0 / 2)      Lines: 25% (1 / 4)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37                      1                                                  
/**
 * @fileoverview Rule to disallow use of new operator with the `require` function
 * @author Wil Moore III
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `new` operators with calls to `require`",
            category: "Node.js and CommonJS",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
 
            NewExpression(node) {
                if (node.callee.type === "Identifier" && node.callee.name === "require") {
                    context.report({ node, message: "Unexpected use of new with require." });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-new-symbol.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-new-symbol.js

Statements: 11.11% (1 / 9)      Branches: 0% (0 / 8)      Functions: 0% (0 / 2)      Lines: 11.11% (1 / 9)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45                      1                                                                  
/**
 * @fileoverview Rule to disallow use of the new operator with the `Symbol` object
 * @author Alberto Rodríguez
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `new` operators with the `Symbol` object",
            category: "ECMAScript 6",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
            "Program:exit"() {
                const globalScope = context.getScope();
                const variable = globalScope.set.get("Symbol");
 
                if (variable && variable.defs.length === 0) {
                    variable.references.forEach(ref => {
                        const node = ref.identifier;
 
                        if (node.parent && node.parent.type === "NewExpression") {
                            context.report({ node, message: "`Symbol` cannot be called as a constructor." });
                        }
                    });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-new-wrappers.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-new-wrappers.js

Statements: 20% (1 / 5)      Branches: 0% (0 / 2)      Functions: 0% (0 / 2)      Lines: 20% (1 / 5)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39                      1                                                      
/**
 * @fileoverview Rule to flag when using constructor for wrapper objects
 * @author Ilya Volodin
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `new` operators with the `String`, `Number`, and `Boolean` objects",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
 
            NewExpression(node) {
                const wrapperObjects = ["String", "Number", "Boolean", "Math", "JSON"];
 
                if (wrapperObjects.indexOf(node.callee.name) > -1) {
                    context.report({ node, message: "Do not use {{fn}} as a constructor.", data: { fn: node.callee.name } });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-new.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-new.js

Statements: 33.33% (1 / 3)      Branches: 100% (0 / 0)      Functions: 0% (0 / 2)      Lines: 33.33% (1 / 3)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35                        1                                            
/**
 * @fileoverview Rule to flag statements with function invocation preceded by
 * "new" and not part of assignment
 * @author Ilya Volodin
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `new` operators outside of assignments or comparisons",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
            "ExpressionStatement > NewExpression"(node) {
                context.report({ node: node.parent, message: "Do not use 'new' for side effects." });
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-obj-calls.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-obj-calls.js

Statements: 16.67% (1 / 6)      Branches: 0% (0 / 7)      Functions: 0% (0 / 2)      Lines: 16.67% (1 / 6)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41                      1                                                          
/**
 * @fileoverview Rule to flag use of an object property of the global object (Math and JSON) as a function
 * @author James Allardice
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow calling global object properties as functions",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
            CallExpression(node) {
 
                if (node.callee.type === "Identifier") {
                    const name = node.callee.name;
 
                    if (name === "Math" || name === "JSON" || name === "Reflect") {
                        context.report({ node, message: "'{{name}}' is not a function.", data: { name } });
                    }
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-octal-escape.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-octal-escape.js

Statements: 11.11% (1 / 9)      Branches: 0% (0 / 8)      Functions: 0% (0 / 2)      Lines: 11.11% (1 / 9)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49                      1                                                                          
/**
 * @fileoverview Rule to flag octal escape sequences in string literals.
 * @author Ian Christian Myers
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow octal escape sequences in string literals",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
 
            Literal(node) {
                if (typeof node.value !== "string") {
                    return;
                }
 
                const match = node.raw.match(/^([^\\]|\\[^0-7])*\\([0-3][0-7]{1,2}|[4-7][0-7]|[0-7])/);
 
                if (match) {
                    const octalDigit = match[2];
 
                    // \0 is actually not considered an octal
                    if (match[2] !== "0" || typeof match[3] !== "undefined") {
                        context.report({ node, message: "Don't use octal: '\\{{octalDigit}}'. Use '\\u....' instead.", data: { octalDigit } });
                    }
                }
            }
 
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-octal.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-octal.js

Statements: 25% (1 / 4)      Branches: 0% (0 / 4)      Functions: 0% (0 / 2)      Lines: 25% (1 / 4)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37                      1                                                  
/**
 * @fileoverview Rule to flag when initializing octal literal
 * @author Ilya Volodin
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow octal literals",
            category: "Best Practices",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
 
            Literal(node) {
                if (typeof node.value === "number" && /^0[0-7]/.test(node.raw)) {
                    context.report({ node, message: "Octal literals should not be used." });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-param-reassign.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-param-reassign.js

Statements: 15.38% (6 / 39)      Branches: 0% (0 / 36)      Functions: 0% (0 / 5)      Lines: 15.38% (6 / 39)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173                    1   1                                                                                                   1                                                                                                                         1                                             1                     1                              
/**
 * @fileoverview Disallow reassignment of function parameters.
 * @author Nat Burns
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
const stopNodePattern = /(?:Statement|Declaration|Function(?:Expression)?|Program)$/;
 
module.exports = {
    meta: {
        docs: {
            description: "disallow reassigning `function` parameters",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [
            {
                oneOf: [
                    {
                        type: "object",
                        properties: {
                            props: {
                                enum: [false]
                            }
                        },
                        additionalProperties: false
                    },
                    {
                        type: "object",
                        properties: {
                            props: {
                                enum: [true]
                            },
                            ignorePropertyModificationsFor: {
                                type: "array",
                                items: {
                                    type: "string"
                                },
                                uniqueItems: true
                            }
                        },
                        additionalProperties: false
                    }
                ]
            }
        ]
    },
 
    create(context) {
        const props = context.options[0] && Boolean(context.options[0].props);
        const ignoredPropertyAssignmentsFor = context.options[0] && context.options[0].ignorePropertyModificationsFor || [];
 
        /**
         * Checks whether or not the reference modifies properties of its variable.
         * @param {Reference} reference - A reference to check.
         * @returns {boolean} Whether or not the reference modifies properties of its variable.
         */
        function isModifyingProp(reference) {
            let node = reference.identifier;
            let parent = node.parent;
 
            while (parent && !stopNodePattern.test(parent.type)) {
                switch (parent.type) {
 
                    // e.g. foo.a = 0;
                    case "AssignmentExpression":
                        return parent.left === node;
 
                    // e.g. ++foo.a;
                    case "UpdateExpression":
                        return true;
 
                    // e.g. delete foo.a;
                    case "UnaryExpression":
                        if (parent.operator === "delete") {
                            return true;
                        }
                        break;
 
                    // EXCLUDES: e.g. cache.get(foo.a).b = 0;
                    case "CallExpression":
                        if (parent.callee !== node) {
                            return false;
                        }
                        break;
 
                    // EXCLUDES: e.g. cache[foo.a] = 0;
                    case "MemberExpression":
                        if (parent.property === node) {
                            return false;
                        }
                        break;
 
                    // EXCLUDES: e.g. ({ [foo]: a }) = bar;
                    case "Property":
                        if (parent.key === node) {
                            return false;
                        }
 
                        break;
 
                    // no default
                }
 
                node = parent;
                parent = node.parent;
            }
 
            return false;
        }
 
        /**
         * Reports a reference if is non initializer and writable.
         * @param {Reference} reference - A reference to check.
         * @param {int} index - The index of the reference in the references.
         * @param {Reference[]} references - The array that the reference belongs to.
         * @returns {void}
         */
        function checkReference(reference, index, references) {
            const identifier = reference.identifier;
 
            if (identifier &&
                !reference.init &&
 
                // Destructuring assignments can have multiple default value,
                // so possibly there are multiple writeable references for the same identifier.
                (index === 0 || references[index - 1].identifier !== identifier)
            ) {
                if (reference.isWrite()) {
                    context.report({ node: identifier, message: "Assignment to function parameter '{{name}}'.", data: { name: identifier.name } });
                } else if (props && isModifyingProp(reference) && ignoredPropertyAssignmentsFor.indexOf(identifier.name) === -1) {
                    context.report({ node: identifier, message: "Assignment to property of function parameter '{{name}}'.", data: { name: identifier.name } });
                }
            }
        }
 
        /**
         * Finds and reports references that are non initializer and writable.
         * @param {Variable} variable - A variable to check.
         * @returns {void}
         */
        function checkVariable(variable) {
            if (variable.defs[0].type === "Parameter") {
                variable.references.forEach(checkReference);
            }
        }
 
        /**
         * Checks parameters of a given function node.
         * @param {ASTNode} node - A function node to check.
         * @returns {void}
         */
        function checkForFunction(node) {
            context.getDeclaredVariables(node).forEach(checkVariable);
        }
 
        return {
 
            // `:exit` is needed for the `node.parent` property of identifier nodes.
            "FunctionDeclaration:exit": checkForFunction,
            "FunctionExpression:exit": checkForFunction,
            "ArrowFunctionExpression:exit": checkForFunction
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-path-concat.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-path-concat.js

Statements: 16.67% (1 / 6)      Branches: 0% (0 / 7)      Functions: 0% (0 / 2)      Lines: 16.67% (1 / 6)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51                    1                                                                                
/**
 * @fileoverview Disallow string concatenation when using __dirname and __filename
 * @author Nicholas C. Zakas
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow string concatenation with `__dirname` and `__filename`",
            category: "Node.js and CommonJS",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        const MATCHER = /^__(?:dir|file)name$/;
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
 
            BinaryExpression(node) {
 
                const left = node.left,
                    right = node.right;
 
                if (node.operator === "+" &&
                        ((left.type === "Identifier" && MATCHER.test(left.name)) ||
                        (right.type === "Identifier" && MATCHER.test(right.name)))
                ) {
 
                    context.report({ node, message: "Use path.join() or path.resolve() instead of + to create paths." });
                }
            }
 
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-plusplus.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-plusplus.js

Statements: 11.11% (1 / 9)      Branches: 0% (0 / 6)      Functions: 0% (0 / 2)      Lines: 11.11% (1 / 9)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63                        1                                                                                                    
/**
 * @fileoverview Rule to flag use of unary increment and decrement operators.
 * @author Ian Christian Myers
 * @author Brody McKee (github.com/mrmckeb)
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow the unary operators `++` and `--`",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    allowForLoopAfterthoughts: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        const config = context.options[0];
        let allowInForAfterthought = false;
 
        if (typeof config === "object") {
            allowInForAfterthought = config.allowForLoopAfterthoughts === true;
        }
 
        return {
 
            UpdateExpression(node) {
                if (allowInForAfterthought && node.parent.type === "ForStatement") {
                    return;
                }
                context.report({
                    node,
                    message: "Unary operator '{{operator}}' used.",
                    data: {
                        operator: node.operator
                    }
                });
            }
 
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-process-env.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-process-env.js

Statements: 20% (1 / 5)      Branches: 0% (0 / 6)      Functions: 0% (0 / 2)      Lines: 20% (1 / 5)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41                    1                                                            
/**
 * @fileoverview Disallow the use of process.env()
 * @author Vignesh Anand
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow the use of `process.env`",
            category: "Node.js and CommonJS",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
 
            MemberExpression(node) {
                const objectName = node.object.name,
                    propertyName = node.property.name;
 
                if (objectName === "process" && !node.computed && propertyName && propertyName === "env") {
                    context.report({ node, message: "Unexpected use of process.env." });
                }
 
            }
 
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-process-exit.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-process-exit.js

Statements: 33.33% (1 / 3)      Branches: 100% (0 / 0)      Functions: 0% (0 / 2)      Lines: 33.33% (1 / 3)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37                    1                                                    
/**
 * @fileoverview Disallow the use of process.exit()
 * @author Nicholas C. Zakas
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow the use of `process.exit()`",
            category: "Node.js and CommonJS",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            "CallExpression > MemberExpression.callee[object.name = 'process'][property.name = 'exit']"(node) {
                context.report({ node: node.parent, message: "Don't use process.exit(); throw an error instead." });
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-proto.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-proto.js

Statements: 25% (1 / 4)      Branches: 0% (0 / 8)      Functions: 0% (0 / 2)      Lines: 25% (1 / 4)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40                      1                                                        
/**
 * @fileoverview Rule to flag usage of __proto__ property
 * @author Ilya Volodin
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow the use of the `__proto__` property",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
 
            MemberExpression(node) {
 
                if (node.property &&
                        (node.property.type === "Identifier" && node.property.name === "__proto__" && !node.computed) ||
                        (node.property.type === "Literal" && node.property.value === "__proto__")) {
                    context.report({ node, message: "The '__proto__' property is deprecated." });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-prototype-builtins.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-prototype-builtins.js

Statements: 22.22% (2 / 9)      Branches: 0% (0 / 6)      Functions: 0% (0 / 2)      Lines: 22.22% (2 / 9)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56                    1                                             1                                            
/**
 * @fileoverview Rule to disallow use of Object.prototype builtins on objects
 * @author Andrew Levine
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow calling some `Object.prototype` methods directly on objects",
            category: "Possible Errors",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
        const DISALLOWED_PROPS = [
            "hasOwnProperty",
            "isPrototypeOf",
            "propertyIsEnumerable"
        ];
 
        /**
         * Reports if a disallowed property is used in a CallExpression
         * @param {ASTNode} node The CallExpression node.
         * @returns {void}
         */
        function disallowBuiltIns(node) {
            if (node.callee.type !== "MemberExpression" || node.callee.computed) {
                return;
            }
            const propName = node.callee.property.name;
 
            if (DISALLOWED_PROPS.indexOf(propName) > -1) {
                context.report({
                    message: "Do not access Object.prototype method '{{prop}}' from target object.",
                    loc: node.callee.property.loc.start,
                    data: { prop: propName },
                    node
                });
            }
        }
 
        return {
            CallExpression: disallowBuiltIns
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-redeclare.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-redeclare.js

Statements: 19.05% (4 / 21)      Branches: 0% (0 / 16)      Functions: 0% (0 / 4)      Lines: 20% (4 / 20)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103                      1                                                           1                                           1                                   1                                          
/**
 * @fileoverview Rule to flag when the same variable is declared more then once.
 * @author Ilya Volodin
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow variable redeclaration",
            category: "Best Practices",
            recommended: true
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    builtinGlobals: { type: "boolean" }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const options = {
            builtinGlobals: Boolean(context.options[0] && context.options[0].builtinGlobals)
        };
 
        /**
         * Find variables in a given scope and flag redeclared ones.
         * @param {Scope} scope - An escope scope object.
         * @returns {void}
         * @private
         */
        function findVariablesInScope(scope) {
            scope.variables.forEach(variable => {
                const hasBuiltin = options.builtinGlobals && "writeable" in variable;
                const count = (hasBuiltin ? 1 : 0) + variable.identifiers.length;
 
                if (count >= 2) {
                    variable.identifiers.sort((a, b) => a.range[1] - b.range[1]);
 
                    for (let i = (hasBuiltin ? 0 : 1), l = variable.identifiers.length; i < l; i++) {
                        context.report({ node: variable.identifiers[i], message: "'{{a}}' is already defined.", data: { a: variable.name } });
                    }
                }
            });
 
        }
 
        /**
         * Find variables in the current scope.
         * @param {ASTNode} node - The Program node.
         * @returns {void}
         * @private
         */
        function checkForGlobal(node) {
            const scope = context.getScope(),
                parserOptions = context.parserOptions,
                ecmaFeatures = parserOptions.ecmaFeatures || {};
 
            // Nodejs env or modules has a special scope.
            if (ecmaFeatures.globalReturn || node.sourceType === "module") {
                findVariablesInScope(scope.childScopes[0]);
            } else {
                findVariablesInScope(scope);
            }
        }
 
        /**
         * Find variables in the current scope.
         * @returns {void}
         * @private
         */
        function checkForBlock() {
            findVariablesInScope(context.getScope());
        }
 
        if (context.parserOptions.ecmaVersion >= 6) {
            return {
                Program: checkForGlobal,
                BlockStatement: checkForBlock,
                SwitchStatement: checkForBlock
            };
        }
        return {
            Program: checkForGlobal,
            FunctionDeclaration: checkForBlock,
            FunctionExpression: checkForBlock,
            ArrowFunctionExpression: checkForBlock
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-regex-spaces.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-regex-spaces.js

Statements: 27.27% (6 / 22)      Branches: 0% (0 / 15)      Functions: 0% (0 / 6)      Lines: 27.27% (6 / 22)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116              1           1                                                 1                                                               1                               1                   1                                      
/**
 * @fileoverview Rule to count multiple spaces in regular expressions
 * @author Matt DuVall <http://www.mattduvall.com/>
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow multiple spaces in regular expressions",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: [],
 
        fixable: "code"
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        /**
         * Validate regular expressions
         * @param {ASTNode} node node to validate
         * @param {string} value regular expression to validate
         * @param {number} valueStart The start location of the regex/string literal. It will always be the case that
         `sourceCode.getText().slice(valueStart, valueStart + value.length) === value`
         * @returns {void}
         * @private
         */
        function checkRegex(node, value, valueStart) {
            const multipleSpacesRegex = /( {2,})+?/,
                regexResults = multipleSpacesRegex.exec(value);
 
            if (regexResults !== null) {
                const count = regexResults[0].length;
 
                context.report({
                    node,
                    message: "Spaces are hard to count. Use {{{count}}}.",
                    data: { count },
                    fix(fixer) {
                        return fixer.replaceTextRange(
                            [valueStart + regexResults.index, valueStart + regexResults.index + count],
                            ` {${count}}`
                        );
                    }
                });
 
                /*
                 * TODO: (platinumazure) Fix message to use rule message
                 * substitution when api.report is fixed in lib/eslint.js.
                 */
            }
        }
 
        /**
         * Validate regular expression literals
         * @param {ASTNode} node node to validate
         * @returns {void}
         * @private
         */
        function checkLiteral(node) {
            const token = sourceCode.getFirstToken(node),
                nodeType = token.type,
                nodeValue = token.value;
 
            if (nodeType === "RegularExpression") {
                checkRegex(node, nodeValue, token.start);
            }
        }
 
        /**
         * Check if node is a string
         * @param {ASTNode} node node to evaluate
         * @returns {boolean} True if its a string
         * @private
         */
        function isString(node) {
            return node && node.type === "Literal" && typeof node.value === "string";
        }
 
        /**
         * Validate strings passed to the RegExp constructor
         * @param {ASTNode} node node to validate
         * @returns {void}
         * @private
         */
        function checkFunction(node) {
            const scope = context.getScope();
            const regExpVar = astUtils.getVariableByName(scope, "RegExp");
            const shadowed = regExpVar && regExpVar.defs.length > 0;
 
            if (node.callee.type === "Identifier" && node.callee.name === "RegExp" && isString(node.arguments[0]) && !shadowed) {
                checkRegex(node, node.arguments[0].value, node.arguments[0].start + 1);
            }
        }
 
        return {
            Literal: checkLiteral,
            CallExpression: checkFunction,
            NewExpression: checkFunction
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-restricted-globals.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-restricted-globals.js

Statements: 18.75% (3 / 16)      Branches: 0% (0 / 8)      Functions: 0% (0 / 4)      Lines: 18.75% (3 / 16)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81                    1                                                             1                       1                                                      
/**
 * @fileoverview Restrict usage of specified globals.
 * @author Benoît Zugmeyer
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow specified global variables",
            category: "Variables",
            recommended: false
        },
 
        schema: {
            type: "array",
            items: {
                type: "string"
            },
            uniqueItems: true
        }
    },
 
    create(context) {
        const restrictedGlobals = context.options;
 
        // if no globals are restricted we don't need to check
        if (restrictedGlobals.length === 0) {
            return {};
        }
 
        /**
         * Report a variable to be used as a restricted global.
         * @param {Reference} reference the variable reference
         * @returns {void}
         * @private
         */
        function reportReference(reference) {
            context.report({ node: reference.identifier, message: "Unexpected use of '{{name}}'.", data: {
                name: reference.identifier.name
            } });
        }
 
        /**
         * Check if the given name is a restricted global name.
         * @param {string} name name of a variable
         * @returns {boolean} whether the variable is a restricted global or not
         * @private
         */
        function isRestricted(name) {
            return restrictedGlobals.indexOf(name) >= 0;
        }
 
        return {
            Program() {
                const scope = context.getScope();
 
                // Report variables declared elsewhere (ex: variables defined as "global" by eslint)
                scope.variables.forEach(variable => {
                    if (!variable.defs.length && isRestricted(variable.name)) {
                        variable.references.forEach(reportReference);
                    }
                });
 
                // Report variables not declared at all
                scope.through.forEach(reference => {
                    if (isRestricted(reference.identifier.name)) {
                        reportReference(reference);
                    }
                });
 
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-restricted-imports.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-restricted-imports.js

Statements: 17.65% (3 / 17)      Branches: 0% (0 / 25)      Functions: 0% (0 / 2)      Lines: 17.65% (3 / 17)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87                    1   1               1                                                                                                                                    
/**
 * @fileoverview Restrict usage of specified node imports.
 * @author Guy Ellis
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
const ignore = require("ignore");
 
const arrayOfStrings = {
    type: "array",
    items: {
        type: "string"
    },
    uniqueItems: true
};
 
module.exports = {
    meta: {
        docs: {
            description: "disallow specified modules when loaded by `import`",
            category: "ECMAScript 6",
            recommended: false
        },
 
        schema: {
            anyOf: [
                arrayOfStrings,
                {
                    type: "array",
                    items: [{
                        type: "object",
                        properties: {
                            paths: arrayOfStrings,
                            patterns: arrayOfStrings
                        },
                        additionalProperties: false
                    }],
                    additionalItems: false
                }
            ]
        }
    },
 
    create(context) {
        const options = Array.isArray(context.options) ? context.options : [];
        const isStringArray = typeof options[0] !== "object";
        const restrictedPaths = new Set(isStringArray ? context.options : options[0].paths || []);
        const restrictedPatterns = isStringArray ? [] : options[0].patterns || [];
 
        // if no imports are restricted we don"t need to check
        if (restrictedPaths.size === 0 && restrictedPatterns.length === 0) {
            return {};
        }
 
        const ig = ignore().add(restrictedPatterns);
 
        return {
            ImportDeclaration(node) {
                if (node && node.source && node.source.value) {
 
                    const importName = node.source.value.trim();
 
                    if (restrictedPaths.has(importName)) {
                        context.report({
                            node,
                            message: "'{{importName}}' import is restricted from being used.",
                            data: { importName }
                        });
                    }
                    if (restrictedPatterns.length > 0 && ig.ignores(importName)) {
                        context.report({
                            node,
                            message: "'{{importName}}' import is restricted from being used by a pattern.",
                            data: { importName }
                        });
                    }
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-restricted-modules.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-restricted-modules.js

Statements: 22.73% (5 / 22)      Branches: 0% (0 / 31)      Functions: 0% (0 / 4)      Lines: 22.73% (5 / 22)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110                    1   1               1                                                                                         1                 1                                                                      
/**
 * @fileoverview Restrict usage of specified node modules.
 * @author Christian Schulz
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
const ignore = require("ignore");
 
const arrayOfStrings = {
    type: "array",
    items: {
        type: "string"
    },
    uniqueItems: true
};
 
module.exports = {
    meta: {
        docs: {
            description: "disallow specified modules when loaded by `require`",
            category: "Node.js and CommonJS",
            recommended: false
        },
 
        schema: {
            anyOf: [
                arrayOfStrings,
                {
                    type: "array",
                    items: [{
                        type: "object",
                        properties: {
                            paths: arrayOfStrings,
                            patterns: arrayOfStrings
                        },
                        additionalProperties: false
                    }],
                    additionalItems: false
                }
            ]
        }
    },
 
    create(context) {
        const options = Array.isArray(context.options) ? context.options : [];
        const isStringArray = typeof options[0] !== "object";
        const restrictedPaths = new Set(isStringArray ? context.options : options[0].paths || []);
        const restrictedPatterns = isStringArray ? [] : options[0].patterns || [];
 
        // if no imports are restricted we don"t need to check
        if (restrictedPaths.size === 0 && restrictedPatterns.length === 0) {
            return {};
        }
 
        const ig = ignore().add(restrictedPatterns);
 
        /**
         * Function to check if a node is a string literal.
         * @param {ASTNode} node The node to check.
         * @returns {boolean} If the node is a string literal.
         */
        function isString(node) {
            return node && node.type === "Literal" && typeof node.value === "string";
        }
 
        /**
         * Function to check if a node is a require call.
         * @param {ASTNode} node The node to check.
         * @returns {boolean} If the node is a require call.
         */
        function isRequireCall(node) {
            return node.callee.type === "Identifier" && node.callee.name === "require";
        }
 
        return {
            CallExpression(node) {
                if (isRequireCall(node)) {
 
                    // node has arguments and first argument is string
                    if (node.arguments.length && isString(node.arguments[0])) {
                        const moduleName = node.arguments[0].value.trim();
 
                        // check if argument value is in restricted modules array
                        if (restrictedPaths.has(moduleName)) {
                            context.report({
                                node,
                                message: "'{{moduleName}}' module is restricted from being used.",
                                data: { moduleName }
                            });
                        }
 
                        if (restrictedPatterns.length > 0 && ig.ignores(moduleName)) {
                            context.report({
                                node,
                                message: "'{{moduleName}}' module is restricted from being used by a pattern.",
                                data: { moduleName }
                            });
                        }
                    }
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-restricted-properties.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-restricted-properties.js

Statements: 9.3% (4 / 43)      Branches: 0% (0 / 32)      Functions: 0% (0 / 5)      Lines: 9.3% (4 / 43)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167              1           1                                                                                                                                                                             1                                                                 1                                                                  
/**
 * @fileoverview Rule to disallow certain object properties
 * @author Will Klein & Eli White
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow certain properties on certain objects",
            category: "Best Practices",
            recommended: false
        },
 
        schema: {
            type: "array",
            items: {
                anyOf: [ // `object` and `property` are both optional, but at least one of them must be provided.
                    {
                        type: "object",
                        properties: {
                            object: {
                                type: "string"
                            },
                            property: {
                                type: "string"
                            },
                            message: {
                                type: "string"
                            }
                        },
                        additionalProperties: false,
                        required: ["object"]
                    },
                    {
                        type: "object",
                        properties: {
                            object: {
                                type: "string"
                            },
                            property: {
                                type: "string"
                            },
                            message: {
                                type: "string"
                            }
                        },
                        additionalProperties: false,
                        required: ["property"]
                    }
                ]
            },
            uniqueItems: true
        }
    },
 
    create(context) {
        const restrictedCalls = context.options;
 
        if (restrictedCalls.length === 0) {
            return {};
        }
 
        const restrictedProperties = new Map();
        const globallyRestrictedObjects = new Map();
        const globallyRestrictedProperties = new Map();
 
        restrictedCalls.forEach(option => {
            const objectName = option.object;
            const propertyName = option.property;
 
            if (typeof objectName === "undefined") {
                globallyRestrictedProperties.set(propertyName, { message: option.message });
            } else if (typeof propertyName === "undefined") {
                globallyRestrictedObjects.set(objectName, { message: option.message });
            } else {
                if (!restrictedProperties.has(objectName)) {
                    restrictedProperties.set(objectName, new Map());
                }
 
                restrictedProperties.get(objectName).set(propertyName, {
                    message: option.message
                });
            }
        });
 
        /**
        * Checks to see whether a property access is restricted, and reports it if so.
        * @param {ASTNode} node The node to report
        * @param {string} objectName The name of the object
        * @param {string} propertyName The name of the property
        * @returns {undefined}
        */
        function checkPropertyAccess(node, objectName, propertyName) {
            if (propertyName === null) {
                return;
            }
            const matchedObject = restrictedProperties.get(objectName);
            const matchedObjectProperty = matchedObject ? matchedObject.get(propertyName) : globallyRestrictedObjects.get(objectName);
            const globalMatchedProperty = globallyRestrictedProperties.get(propertyName);
 
            if (matchedObjectProperty) {
                const message = matchedObjectProperty.message ? ` ${matchedObjectProperty.message}` : "";
 
                // eslint-disable-next-line eslint-plugin/report-message-format
                context.report({ node, message: "'{{objectName}}.{{propertyName}}' is restricted from being used.{{message}}", data: {
                    objectName,
                    propertyName,
                    message
                } });
            } else if (globalMatchedProperty) {
                const message = globalMatchedProperty.message ? ` ${globalMatchedProperty.message}` : "";
 
                // eslint-disable-next-line eslint-plugin/report-message-format
                context.report({ node, message: "'{{propertyName}}' is restricted from being used.{{message}}", data: {
                    propertyName,
                    message
                } });
            }
        }
 
        /**
        * Checks property accesses in a destructuring assignment expression, e.g. `var foo; ({foo} = bar);`
        * @param {ASTNode} node An AssignmentExpression or AssignmentPattern node
        * @returns {undefined}
        */
        function checkDestructuringAssignment(node) {
            if (node.right.type === "Identifier") {
                const objectName = node.right.name;
 
                if (node.left.type === "ObjectPattern") {
                    node.left.properties.forEach(property => {
                        checkPropertyAccess(node.left, objectName, astUtils.getStaticPropertyName(property));
                    });
                }
            }
        }
 
        return {
            MemberExpression(node) {
                checkPropertyAccess(node, node.object && node.object.name, astUtils.getStaticPropertyName(node));
            },
            VariableDeclarator(node) {
                if (node.init && node.init.type === "Identifier") {
                    const objectName = node.init.name;
 
                    if (node.id.type === "ObjectPattern") {
                        node.id.properties.forEach(property => {
                            checkPropertyAccess(node.id, objectName, astUtils.getStaticPropertyName(property));
                        });
                    }
                }
            },
            AssignmentExpression: checkDestructuringAssignment,
            AssignmentPattern: checkDestructuringAssignment
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-restricted-syntax.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-restricted-syntax.js

Statements: 12.5% (1 / 8)      Branches: 0% (0 / 8)      Functions: 0% (0 / 2)      Lines: 12.5% (1 / 8)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64                    1                                                                                                          
/**
 * @fileoverview Rule to flag use of certain node types
 * @author Burak Yigit Kaya
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow specified syntax",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: {
            type: "array",
            items: [{
                oneOf: [
                    {
                        type: "string"
                    },
                    {
                        type: "object",
                        properties: {
                            selector: { type: "string" },
                            message: { type: "string" }
                        },
                        required: ["selector"],
                        additionalProperties: false
                    }
                ]
            }],
            uniqueItems: true,
            minItems: 0
        }
    },
 
    create(context) {
        return context.options.reduce((result, selectorOrObject) => {
            const isStringFormat = (typeof selectorOrObject === "string");
            const hasCustomMessage = !isStringFormat && Boolean(selectorOrObject.message);
 
            const selector = isStringFormat ? selectorOrObject : selectorOrObject.selector;
            const message = hasCustomMessage ? selectorOrObject.message : "Using '{{selector}}' is not allowed.";
 
            return Object.assign(result, {
                [selector](node) {
                    context.report({
                        node,
                        message,
                        data: hasCustomMessage ? {} : { selector }
                    });
                }
            });
        }, {});
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-return-assign.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-return-assign.js

Statements: 18.75% (3 / 16)      Branches: 0% (0 / 17)      Functions: 0% (0 / 2)      Lines: 18.75% (3 / 16)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73                    1           1           1                                                                                                    
/**
 * @fileoverview Rule to flag when return statement contains assignment
 * @author Ilya Volodin
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const SENTINEL_TYPE = /^(?:[a-zA-Z]+?Statement|ArrowFunctionExpression|FunctionExpression|ClassExpression)$/;
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow assignment operators in `return` statements",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [
            {
                enum: ["except-parens", "always"]
            }
        ]
    },
 
    create(context) {
        const always = (context.options[0] || "except-parens") !== "except-parens";
        const sourceCode = context.getSourceCode();
 
        return {
            AssignmentExpression(node) {
                if (!always && astUtils.isParenthesised(sourceCode, node)) {
                    return;
                }
 
                let parent = node.parent;
 
                // Find ReturnStatement or ArrowFunctionExpression in ancestors.
                while (parent && !SENTINEL_TYPE.test(parent.type)) {
                    node = parent;
                    parent = parent.parent;
                }
 
                // Reports.
                if (parent && parent.type === "ReturnStatement") {
                    context.report({
                        node: parent,
                        message: "Return statement should not contain assignment."
                    });
                } else if (parent && parent.type === "ArrowFunctionExpression" && parent.body === node) {
                    context.report({
                        node: parent,
                        message: "Arrow function should not return assignment."
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-return-await.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-return-await.js

Statements: 22.22% (6 / 27)      Branches: 0% (0 / 29)      Functions: 0% (0 / 5)      Lines: 22.22% (6 / 27)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96            1           1   1                                     1                             1                                   1                                                          
/**
 * @fileoverview Disallows unnecessary `return await`
 * @author Jordan Harband
 */
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
const message = "Redundant use of `await` on a return value.";
 
module.exports = {
    meta: {
        docs: {
            description: "disallow unnecessary `return await`",
            category: "Best Practices",
            recommended: false // TODO: set to true
        },
        fixable: null,
        schema: [
        ]
    },
 
    create(context) {
 
        /**
         * Reports a found unnecessary `await` expression.
         * @param {ASTNode} node The node representing the `await` expression to report
         * @returns {void}
         */
        function reportUnnecessaryAwait(node) {
            context.report({
                node: context.getSourceCode().getFirstToken(node),
                loc: node.loc,
                message
            });
        }
 
        /**
        * Determines whether a thrown error from this node will be caught/handled within this function rather than immediately halting
        * this function. For example, a statement in a `try` block will always have an error handler. A statement in
        * a `catch` block will only have an error handler if there is also a `finally` block.
        * @param {ASTNode} node A node representing a location where an could be thrown
        * @returns {boolean} `true` if a thrown error will be caught/handled in this function
        */
        function hasErrorHandler(node) {
            let ancestor = node;
 
            while (!astUtils.isFunction(ancestor) && ancestor.type !== "Program") {
                if (ancestor.parent.type === "TryStatement" && (ancestor === ancestor.parent.block || ancestor === ancestor.parent.handler && ancestor.parent.finalizer)) {
                    return true;
                }
                ancestor = ancestor.parent;
            }
            return false;
        }
 
        /**
         * Checks if a node is placed in tail call position. Once `return` arguments (or arrow function expressions) can be a complex expression,
         * an `await` expression could or could not be unnecessary by the definition of this rule. So we're looking for `await` expressions that are in tail position.
         * @param {ASTNode} node A node representing the `await` expression to check
         * @returns {boolean} The checking result
         */
        function isInTailCallPosition(node) {
            if (node.parent.type === "ArrowFunctionExpression") {
                return true;
            }
            if (node.parent.type === "ReturnStatement") {
                return !hasErrorHandler(node.parent);
            }
            if (node.parent.type === "ConditionalExpression" && (node === node.parent.consequent || node === node.parent.alternate)) {
                return isInTailCallPosition(node.parent);
            }
            if (node.parent.type === "LogicalExpression" && node === node.parent.right) {
                return isInTailCallPosition(node.parent);
            }
            if (node.parent.type === "SequenceExpression" && node === node.parent.expressions[node.parent.expressions.length - 1]) {
                return isInTailCallPosition(node.parent);
            }
            return false;
        }
 
        return {
            AwaitExpression(node) {
                if (isInTailCallPosition(node) && !hasErrorHandler(node)) {
                    reportUnnecessaryAwait(node);
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-script-url.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-script-url.js

Statements: 16.67% (1 / 6)      Branches: 0% (0 / 6)      Functions: 0% (0 / 2)      Lines: 16.67% (1 / 6)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43                          1                                                          
/**
 * @fileoverview Rule to flag when using javascript: urls
 * @author Ilya Volodin
 */
/* jshint scripturl: true */
/* eslint no-script-url: 0 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `javascript:` urls",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
 
            Literal(node) {
                if (node.value && typeof node.value === "string") {
                    const value = node.value.toLowerCase();
 
                    if (value.indexOf("javascript:") === 0) {
                        context.report({ node, message: "Script URL is a form of eval." });
                    }
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-self-assign.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-self-assign.js

Statements: 13.21% (7 / 53)      Branches: 0% (0 / 63)      Functions: 0% (0 / 6)      Lines: 13.21% (7 / 53)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214                      1           1                   1                                               1                                                       1                                                                                                                                                                   1                                                               1                                        
/**
 * @fileoverview Rule to disallow assignments where both sides are exactly the same
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const SPACES = /\s+/g;
 
/**
 * Checks whether the property of 2 given member expression nodes are the same
 * property or not.
 *
 * @param {ASTNode} left - A member expression node to check.
 * @param {ASTNode} right - Another member expression node to check.
 * @returns {boolean} `true` if the member expressions have the same property.
 */
function isSameProperty(left, right) {
    if (left.property.type === "Identifier" &&
        left.property.type === right.property.type &&
        left.property.name === right.property.name &&
        left.computed === right.computed
    ) {
        return true;
    }
 
    const lname = astUtils.getStaticPropertyName(left);
    const rname = astUtils.getStaticPropertyName(right);
 
    return lname !== null && lname === rname;
}
 
/**
 * Checks whether 2 given member expression nodes are the reference to the same
 * property or not.
 *
 * @param {ASTNode} left - A member expression node to check.
 * @param {ASTNode} right - Another member expression node to check.
 * @returns {boolean} `true` if the member expressions are the reference to the
 *  same property or not.
 */
function isSameMember(left, right) {
    if (!isSameProperty(left, right)) {
        return false;
    }
 
    const lobj = left.object;
    const robj = right.object;
 
    if (lobj.type !== robj.type) {
        return false;
    }
    if (lobj.type === "MemberExpression") {
        return isSameMember(lobj, robj);
    }
    return lobj.type === "Identifier" && lobj.name === robj.name;
}
 
/**
 * Traverses 2 Pattern nodes in parallel, then reports self-assignments.
 *
 * @param {ASTNode|null} left - A left node to traverse. This is a Pattern or
 *      a Property.
 * @param {ASTNode|null} right - A right node to traverse. This is a Pattern or
 *      a Property.
 * @param {boolean} props - The flag to check member expressions as well.
 * @param {Function} report - A callback function to report.
 * @returns {void}
 */
function eachSelfAssignment(left, right, props, report) {
    if (!left || !right) {
 
        // do nothing
    } else if (
        left.type === "Identifier" &&
        right.type === "Identifier" &&
        left.name === right.name
    ) {
        report(right);
    } else if (
        left.type === "ArrayPattern" &&
        right.type === "ArrayExpression"
    ) {
        const end = Math.min(left.elements.length, right.elements.length);
 
        for (let i = 0; i < end; ++i) {
            const rightElement = right.elements[i];
 
            eachSelfAssignment(left.elements[i], rightElement, props, report);
 
            // After a spread element, those indices are unknown.
            if (rightElement && rightElement.type === "SpreadElement") {
                break;
            }
        }
    } else if (
        left.type === "RestElement" &&
        right.type === "SpreadElement"
    ) {
        eachSelfAssignment(left.argument, right.argument, props, report);
    } else if (
        left.type === "ObjectPattern" &&
        right.type === "ObjectExpression" &&
        right.properties.length >= 1
    ) {
 
        // Gets the index of the last spread property.
        // It's possible to overwrite properties followed by it.
        let startJ = 0;
 
        for (let i = right.properties.length - 1; i >= 0; --i) {
            if (right.properties[i].type === "ExperimentalSpreadProperty") {
                startJ = i + 1;
                break;
            }
        }
 
        for (let i = 0; i < left.properties.length; ++i) {
            for (let j = startJ; j < right.properties.length; ++j) {
                eachSelfAssignment(
                    left.properties[i],
                    right.properties[j],
                    props,
                    report
                );
            }
        }
    } else if (
        left.type === "Property" &&
        right.type === "Property" &&
        !left.computed &&
        !right.computed &&
        right.kind === "init" &&
        !right.method &&
        left.key.name === right.key.name
    ) {
        eachSelfAssignment(left.value, right.value, props, report);
    } else if (
        props &&
        left.type === "MemberExpression" &&
        right.type === "MemberExpression" &&
        isSameMember(left, right)
    ) {
        report(right);
    }
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow assignments where both sides are exactly the same",
            category: "Best Practices",
            recommended: true
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    props: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
        const options = context.options[0];
        const props = Boolean(options && options.props);
 
        /**
         * Reports a given node as self assignments.
         *
         * @param {ASTNode} node - A node to report. This is an Identifier node.
         * @returns {void}
         */
        function report(node) {
            context.report({
                node,
                message: "'{{name}}' is assigned to itself.",
                data: {
                    name: sourceCode.getText(node).replace(SPACES, "")
                }
            });
        }
 
        return {
            AssignmentExpression(node) {
                if (node.operator === "=") {
                    eachSelfAssignment(node.left, node.right, props, report);
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-self-compare.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-self-compare.js

Statements: 20% (1 / 5)      Branches: 0% (0 / 9)      Functions: 0% (0 / 2)      Lines: 20% (1 / 5)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42                        1                                                          
/**
 * @fileoverview Rule to flag comparison where left part is the same as the right
 * part.
 * @author Ilya Volodin
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow comparisons where both sides are exactly the same",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
 
            BinaryExpression(node) {
                const operators = ["===", "==", "!==", "!=", ">", "<", ">=", "<="];
 
                if (operators.indexOf(node.operator) > -1 &&
                    (node.left.type === "Identifier" && node.right.type === "Identifier" && node.left.name === node.right.name ||
                    node.left.type === "Literal" && node.right.type === "Literal" && node.left.value === node.right.value)) {
                    context.report({ node, message: "Comparing to itself is potentially pointless." });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-sequences.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-sequences.js

Statements: 23.81% (5 / 21)      Branches: 0% (0 / 21)      Functions: 0% (0 / 5)      Lines: 23.81% (5 / 21)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112                      1           1                                                                         1                   1                 1                                                                            
/**
 * @fileoverview Rule to flag use of comma operator
 * @author Brandon Mills
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow comma operators",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        /**
         * Parts of the grammar that are required to have parens.
         */
        const parenthesized = {
            DoWhileStatement: "test",
            IfStatement: "test",
            SwitchStatement: "discriminant",
            WhileStatement: "test",
            WithStatement: "object",
            ArrowFunctionExpression: "body"
 
            // Omitting CallExpression - commas are parsed as argument separators
            // Omitting NewExpression - commas are parsed as argument separators
            // Omitting ForInStatement - parts aren't individually parenthesised
            // Omitting ForStatement - parts aren't individually parenthesised
        };
 
        /**
         * Determines whether a node is required by the grammar to be wrapped in
         * parens, e.g. the test of an if statement.
         * @param {ASTNode} node - The AST node
         * @returns {boolean} True if parens around node belong to parent node.
         */
        function requiresExtraParens(node) {
            return node.parent && parenthesized[node.parent.type] &&
                    node === node.parent[parenthesized[node.parent.type]];
        }
 
        /**
         * Check if a node is wrapped in parens.
         * @param {ASTNode} node - The AST node
         * @returns {boolean} True if the node has a paren on each side.
         */
        function isParenthesised(node) {
            return astUtils.isParenthesised(sourceCode, node);
        }
 
        /**
         * Check if a node is wrapped in two levels of parens.
         * @param {ASTNode} node - The AST node
         * @returns {boolean} True if two parens surround the node on each side.
         */
        function isParenthesisedTwice(node) {
            const previousToken = sourceCode.getTokenBefore(node, 1),
                nextToken = sourceCode.getTokenAfter(node, 1);
 
            return isParenthesised(node) && previousToken && nextToken &&
                astUtils.isOpeningParenToken(previousToken) && previousToken.range[1] <= node.range[0] &&
                astUtils.isClosingParenToken(nextToken) && nextToken.range[0] >= node.range[1];
        }
 
        return {
            SequenceExpression(node) {
 
                // Always allow sequences in for statement update
                if (node.parent.type === "ForStatement" &&
                        (node === node.parent.init || node === node.parent.update)) {
                    return;
                }
 
                // Wrapping a sequence in extra parens indicates intent
                if (requiresExtraParens(node)) {
                    if (isParenthesisedTwice(node)) {
                        return;
                    }
                } else {
                    if (isParenthesised(node)) {
                        return;
                    }
                }
 
                const child = sourceCode.getTokenAfter(node.expressions[0]);
 
                context.report({ node, loc: child.loc.start, message: "Unexpected use of comma operator." });
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-shadow-restricted-names.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-shadow-restricted-names.js

Statements: 13.33% (2 / 15)      Branches: 0% (0 / 6)      Functions: 0% (0 / 7)      Lines: 13.33% (2 / 15)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71                    1                                         1                                                                              
/**
 * @fileoverview Disallow shadowing of NaN, undefined, and Infinity (ES5 section 15.1.1)
 * @author Michael Ficarra
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow identifiers from shadowing restricted names",
            category: "Variables",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        const RESTRICTED = ["undefined", "NaN", "Infinity", "arguments", "eval"];
 
        /**
         * Check if the node name is present inside the restricted list
         * @param {ASTNode} id id to evaluate
         * @returns {void}
         * @private
         */
        function checkForViolation(id) {
            if (RESTRICTED.indexOf(id.name) > -1) {
                context.report({
                    node: id,
                    message: "Shadowing of global property '{{idName}}'.",
                    data: {
                        idName: id.name
                    }
                });
            }
        }
 
        return {
            VariableDeclarator(node) {
                checkForViolation(node.id);
            },
            ArrowFunctionExpression(node) {
                [].map.call(node.params, checkForViolation);
            },
            FunctionExpression(node) {
                if (node.id) {
                    checkForViolation(node.id);
                }
                [].map.call(node.params, checkForViolation);
            },
            FunctionDeclaration(node) {
                if (node.id) {
                    checkForViolation(node.id);
                    [].map.call(node.params, checkForViolation);
                }
            },
            CatchClause(node) {
                checkForViolation(node.param);
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-shadow.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-shadow.js

Statements: 20% (8 / 40)      Branches: 0% (0 / 46)      Functions: 0% (0 / 8)      Lines: 20% (8 / 40)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190                      1           1                                                                               1                         1                               1                                             1                       1                                       1                                                                                                
/**
 * @fileoverview Rule to flag on declaring variables already declared in the outer scope
 * @author Ilya Volodin
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow variable declarations from shadowing variables declared in the outer scope",
            category: "Variables",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    builtinGlobals: { type: "boolean" },
                    hoist: { enum: ["all", "functions", "never"] },
                    allow: {
                        type: "array",
                        items: {
                            type: "string"
                        }
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        const options = {
            builtinGlobals: Boolean(context.options[0] && context.options[0].builtinGlobals),
            hoist: (context.options[0] && context.options[0].hoist) || "functions",
            allow: (context.options[0] && context.options[0].allow) || []
        };
 
        /**
         * Check if variable name is allowed.
         *
         * @param  {ASTNode} variable The variable to check.
         * @returns {boolean} Whether or not the variable name is allowed.
         */
        function isAllowed(variable) {
            return options.allow.indexOf(variable.name) !== -1;
        }
 
        /**
         * Checks if a variable of the class name in the class scope of ClassDeclaration.
         *
         * ClassDeclaration creates two variables of its name into its outer scope and its class scope.
         * So we should ignore the variable in the class scope.
         *
         * @param {Object} variable The variable to check.
         * @returns {boolean} Whether or not the variable of the class name in the class scope of ClassDeclaration.
         */
        function isDuplicatedClassNameVariable(variable) {
            const block = variable.scope.block;
 
            return block.type === "ClassDeclaration" && block.id === variable.identifiers[0];
        }
 
        /**
         * Checks if a variable is inside the initializer of scopeVar.
         *
         * To avoid reporting at declarations such as `var a = function a() {};`.
         * But it should report `var a = function(a) {};` or `var a = function() { function a() {} };`.
         *
         * @param {Object} variable The variable to check.
         * @param {Object} scopeVar The scope variable to look for.
         * @returns {boolean} Whether or not the variable is inside initializer of scopeVar.
         */
        function isOnInitializer(variable, scopeVar) {
            const outerScope = scopeVar.scope;
            const outerDef = scopeVar.defs[0];
            const outer = outerDef && outerDef.parent && outerDef.parent.range;
            const innerScope = variable.scope;
            const innerDef = variable.defs[0];
            const inner = innerDef && innerDef.name.range;
 
            return (
                outer &&
                inner &&
                outer[0] < inner[0] &&
                inner[1] < outer[1] &&
                ((innerDef.type === "FunctionName" && innerDef.node.type === "FunctionExpression") || innerDef.node.type === "ClassExpression") &&
                outerScope === innerScope.upper
            );
        }
 
        /**
         * Get a range of a variable's identifier node.
         * @param {Object} variable The variable to get.
         * @returns {Array|undefined} The range of the variable's identifier node.
         */
        function getNameRange(variable) {
            const def = variable.defs[0];
 
            return def && def.name.range;
        }
 
        /**
         * Checks if a variable is in TDZ of scopeVar.
         * @param {Object} variable The variable to check.
         * @param {Object} scopeVar The variable of TDZ.
         * @returns {boolean} Whether or not the variable is in TDZ of scopeVar.
         */
        function isInTdz(variable, scopeVar) {
            const outerDef = scopeVar.defs[0];
            const inner = getNameRange(variable);
            const outer = getNameRange(scopeVar);
 
            return (
                inner &&
                outer &&
                inner[1] < outer[0] &&
 
                // Excepts FunctionDeclaration if is {"hoist":"function"}.
                (options.hoist !== "functions" || !outerDef || outerDef.node.type !== "FunctionDeclaration")
            );
        }
 
        /**
         * Checks the current context for shadowed variables.
         * @param {Scope} scope - Fixme
         * @returns {void}
         */
        function checkForShadows(scope) {
            const variables = scope.variables;
 
            for (let i = 0; i < variables.length; ++i) {
                const variable = variables[i];
 
                // Skips "arguments" or variables of a class name in the class scope of ClassDeclaration.
                if (variable.identifiers.length === 0 ||
                    isDuplicatedClassNameVariable(variable) ||
                    isAllowed(variable)
                ) {
                    continue;
                }
 
                // Gets shadowed variable.
                const shadowed = astUtils.getVariableByName(scope.upper, variable.name);
 
                if (shadowed &&
                    (shadowed.identifiers.length > 0 || (options.builtinGlobals && "writeable" in shadowed)) &&
                    !isOnInitializer(variable, shadowed) &&
                    !(options.hoist !== "all" && isInTdz(variable, shadowed))
                ) {
                    context.report({
                        node: variable.identifiers[0],
                        message: "'{{name}}' is already declared in the upper scope.",
                        data: variable
                    });
                }
            }
        }
 
        return {
            "Program:exit"() {
                const globalScope = context.getScope();
                const stack = globalScope.childScopes.slice();
 
                while (stack.length) {
                    const scope = stack.pop();
 
                    stack.push.apply(stack, scope.childScopes);
                    checkForShadows(scope);
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-spaced-func.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-spaced-func.js

Statements: 16.67% (2 / 12)      Branches: 0% (0 / 8)      Functions: 0% (0 / 3)      Lines: 16.67% (2 / 12)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77                        1                                                 1                                                                              
/**
 * @fileoverview Rule to check that spaced function application
 * @author Matt DuVall <http://www.mattduvall.com>
 * @deprecated in ESLint v3.3.0
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow spacing between function identifiers and their applications (deprecated)",
            category: "Stylistic Issues",
            recommended: false,
            replacedBy: ["func-call-spacing"]
        },
 
        deprecated: true,
 
        fixable: "whitespace",
        schema: []
    },
 
    create(context) {
 
        const sourceCode = context.getSourceCode();
 
        /**
         * Check if open space is present in a function name
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function detectOpenSpaces(node) {
            const lastCalleeToken = sourceCode.getLastToken(node.callee);
            let prevToken = lastCalleeToken,
                parenToken = sourceCode.getTokenAfter(lastCalleeToken);
 
            // advances to an open parenthesis.
            while (
                parenToken &&
                parenToken.range[1] < node.range[1] &&
                parenToken.value !== "("
            ) {
                prevToken = parenToken;
                parenToken = sourceCode.getTokenAfter(parenToken);
            }
 
            // look for a space between the callee and the open paren
            if (parenToken &&
                parenToken.range[1] < node.range[1] &&
                sourceCode.isSpaceBetweenTokens(prevToken, parenToken)
            ) {
                context.report({
                    node,
                    loc: lastCalleeToken.loc.start,
                    message: "Unexpected space between function name and paren.",
                    fix(fixer) {
                        return fixer.removeRange([prevToken.range[1], parenToken.range[0]]);
                    }
                });
            }
        }
 
        return {
            CallExpression: detectOpenSpaces,
            NewExpression: detectOpenSpaces
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-sparse-arrays.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-sparse-arrays.js

Statements: 20% (1 / 5)      Branches: 0% (0 / 2)      Functions: 0% (0 / 2)      Lines: 20% (1 / 5)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45                    1                                                                    
/**
 * @fileoverview Disallow sparse arrays
 * @author Nicholas C. Zakas
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow sparse arrays",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
 
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
 
            ArrayExpression(node) {
 
                const emptySpot = node.elements.indexOf(null) > -1;
 
                if (emptySpot) {
                    context.report({ node, message: "Unexpected comma in middle of array." });
                }
            }
 
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-sync.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-sync.js

Statements: 33.33% (1 / 3)      Branches: 100% (0 / 0)      Functions: 0% (0 / 2)      Lines: 33.33% (1 / 3)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43                          1                                                          
/**
 * @fileoverview Rule to check for properties whose identifier ends with the string Sync
 * @author Matt DuVall<http://mattduvall.com/>
 */
 
/* jshint node:true */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow synchronous methods",
            category: "Node.js and CommonJS",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
 
            "MemberExpression[property.name=/.*Sync$/]"(node) {
                context.report({
                    node,
                    message: "Unexpected sync method: '{{propertyName}}'.",
                    data: {
                        propertyName: node.property.name
                    }
                });
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-tabs.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-tabs.js

Statements: 28.57% (2 / 7)      Branches: 0% (0 / 2)      Functions: 0% (0 / 2)      Lines: 28.57% (2 / 7)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45                    1           1                                                        
/**
 * @fileoverview Rule to check for tabs inside a file
 * @author Gyandeep Singh
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
const regex = /\t/;
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow all tabs",
            category: "Stylistic Issues",
            recommended: false
        },
        schema: []
    },
 
    create(context) {
        return {
            Program(node) {
                context.getSourceLines().forEach((line, index) => {
                    const match = regex.exec(line);
 
                    if (match) {
                        context.report({ node, loc: {
                            line: index + 1,
                            column: match.index + 1
                        }, message: "Unexpected tab character." });
                    }
                });
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-template-curly-in-string.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-template-curly-in-string.js

Statements: 20% (1 / 5)      Branches: 0% (0 / 4)      Functions: 0% (0 / 2)      Lines: 20% (1 / 5)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39                    1                                                        
/**
 * @fileoverview Warn when using template string syntax in regular strings
 * @author Jeroen Engels
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow template literal placeholder syntax in regular strings",
            category: "Possible Errors",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
        const regex = /\$\{[^}]+\}/;
 
        return {
            Literal(node) {
                if (typeof node.value === "string" && regex.test(node.value)) {
                    context.report({
                        node,
                        message: "Unexpected template string expression."
                    });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-ternary.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-ternary.js

Statements: 33.33% (1 / 3)      Branches: 100% (0 / 0)      Functions: 0% (0 / 2)      Lines: 33.33% (1 / 3)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36                      1                                                
/**
 * @fileoverview Rule to flag use of ternary operators.
 * @author Ian Christian Myers
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow ternary operators",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
 
            ConditionalExpression(node) {
                context.report({ node, message: "Ternary operator used." });
            }
 
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-this-before-super.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-this-before-super.js

Statements: 13.33% (8 / 60)      Branches: 0% (0 / 46)      Functions: 0% (0 / 15)      Lines: 13.33% (8 / 60)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301                      1                         1                       1                                                                         1               1               1                         1                               1                                                                                                                                                                                                                                                                                                                                                                            
/**
 * @fileoverview A rule to disallow using `this`/`super` before `super()`.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks whether or not a given node is a constructor.
 * @param {ASTNode} node - A node to check. This node type is one of
 *   `Program`, `FunctionDeclaration`, `FunctionExpression`, and
 *   `ArrowFunctionExpression`.
 * @returns {boolean} `true` if the node is a constructor.
 */
function isConstructorFunction(node) {
    return (
        node.type === "FunctionExpression" &&
        node.parent.type === "MethodDefinition" &&
        node.parent.kind === "constructor"
    );
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `this`/`super` before calling `super()` in constructors",
            category: "ECMAScript 6",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
 
        /*
         * Information for each constructor.
         * - upper:      Information of the upper constructor.
         * - hasExtends: A flag which shows whether the owner class has a valid
         *   `extends` part.
         * - scope:      The scope of the owner class.
         * - codePath:   The code path of this constructor.
         */
        let funcInfo = null;
 
        /*
         * Information for each code path segment.
         * Each key is the id of a code path segment.
         * Each value is an object:
         * - superCalled:  The flag which shows `super()` called in all code paths.
         * - invalidNodes: The array of invalid ThisExpression and Super nodes.
         */
        let segInfoMap = Object.create(null);
 
        /**
         * Gets whether or not `super()` is called in a given code path segment.
         * @param {CodePathSegment} segment - A code path segment to get.
         * @returns {boolean} `true` if `super()` is called.
         */
        function isCalled(segment) {
            return !segment.reachable || segInfoMap[segment.id].superCalled;
        }
 
        /**
         * Checks whether or not this is in a constructor.
         * @returns {boolean} `true` if this is in a constructor.
         */
        function isInConstructorOfDerivedClass() {
            return Boolean(funcInfo && funcInfo.isConstructor && funcInfo.hasExtends);
        }
 
        /**
         * Checks whether or not this is before `super()` is called.
         * @returns {boolean} `true` if this is before `super()` is called.
         */
        function isBeforeCallOfSuper() {
            return (
                isInConstructorOfDerivedClass(funcInfo) &&
                !funcInfo.codePath.currentSegments.every(isCalled)
            );
        }
 
        /**
         * Sets a given node as invalid.
         * @param {ASTNode} node - A node to set as invalid. This is one of
         *      a ThisExpression and a Super.
         * @returns {void}
         */
        function setInvalid(node) {
            const segments = funcInfo.codePath.currentSegments;
 
            for (let i = 0; i < segments.length; ++i) {
                const segment = segments[i];
 
                if (segment.reachable) {
                    segInfoMap[segment.id].invalidNodes.push(node);
                }
            }
        }
 
        /**
         * Sets the current segment as `super` was called.
         * @returns {void}
         */
        function setSuperCalled() {
            const segments = funcInfo.codePath.currentSegments;
 
            for (let i = 0; i < segments.length; ++i) {
                const segment = segments[i];
 
                if (segment.reachable) {
                    segInfoMap[segment.id].superCalled = true;
                }
            }
        }
 
        return {
 
            /**
             * Adds information of a constructor into the stack.
             * @param {CodePath} codePath - A code path which was started.
             * @param {ASTNode} node - The current node.
             * @returns {void}
             */
            onCodePathStart(codePath, node) {
                if (isConstructorFunction(node)) {
 
                    // Class > ClassBody > MethodDefinition > FunctionExpression
                    const classNode = node.parent.parent.parent;
 
                    funcInfo = {
                        upper: funcInfo,
                        isConstructor: true,
                        hasExtends: Boolean(
                            classNode.superClass &&
                            !astUtils.isNullOrUndefined(classNode.superClass)
                        ),
                        codePath
                    };
                } else {
                    funcInfo = {
                        upper: funcInfo,
                        isConstructor: false,
                        hasExtends: false,
                        codePath
                    };
                }
            },
 
            /**
             * Removes the top of stack item.
             *
             * And this treverses all segments of this code path then reports every
             * invalid node.
             *
             * @param {CodePath} codePath - A code path which was ended.
             * @param {ASTNode} node - The current node.
             * @returns {void}
             */
            onCodePathEnd(codePath) {
                const isDerivedClass = funcInfo.hasExtends;
 
                funcInfo = funcInfo.upper;
                if (!isDerivedClass) {
                    return;
                }
 
                codePath.traverseSegments((segment, controller) => {
                    const info = segInfoMap[segment.id];
 
                    for (let i = 0; i < info.invalidNodes.length; ++i) {
                        const invalidNode = info.invalidNodes[i];
 
                        context.report({
                            message: "'{{kind}}' is not allowed before 'super()'.",
                            node: invalidNode,
                            data: {
                                kind: invalidNode.type === "Super" ? "super" : "this"
                            }
                        });
                    }
 
                    if (info.superCalled) {
                        controller.skip();
                    }
                });
            },
 
            /**
             * Initialize information of a given code path segment.
             * @param {CodePathSegment} segment - A code path segment to initialize.
             * @returns {void}
             */
            onCodePathSegmentStart(segment) {
                if (!isInConstructorOfDerivedClass(funcInfo)) {
                    return;
                }
 
                // Initialize info.
                segInfoMap[segment.id] = {
                    superCalled: (
                        segment.prevSegments.length > 0 &&
                        segment.prevSegments.every(isCalled)
                    ),
                    invalidNodes: []
                };
            },
 
            /**
             * Update information of the code path segment when a code path was
             * looped.
             * @param {CodePathSegment} fromSegment - The code path segment of the
             *      end of a loop.
             * @param {CodePathSegment} toSegment - A code path segment of the head
             *      of a loop.
             * @returns {void}
             */
            onCodePathSegmentLoop(fromSegment, toSegment) {
                if (!isInConstructorOfDerivedClass(funcInfo)) {
                    return;
                }
 
                // Update information inside of the loop.
                funcInfo.codePath.traverseSegments(
                    { first: toSegment, last: fromSegment },
                    (segment, controller) => {
                        const info = segInfoMap[segment.id];
 
                        if (info.superCalled) {
                            info.invalidNodes = [];
                            controller.skip();
                        } else if (
                            segment.prevSegments.length > 0 &&
                            segment.prevSegments.every(isCalled)
                        ) {
                            info.superCalled = true;
                            info.invalidNodes = [];
                        }
                    }
                );
            },
 
            /**
             * Reports if this is before `super()`.
             * @param {ASTNode} node - A target node.
             * @returns {void}
             */
            ThisExpression(node) {
                if (isBeforeCallOfSuper()) {
                    setInvalid(node);
                }
            },
 
            /**
             * Reports if this is before `super()`.
             * @param {ASTNode} node - A target node.
             * @returns {void}
             */
            Super(node) {
                if (!astUtils.isCallee(node) && isBeforeCallOfSuper()) {
                    setInvalid(node);
                }
            },
 
            /**
             * Marks `super()` called.
             * @param {ASTNode} node - A target node.
             * @returns {void}
             */
            "CallExpression:exit"(node) {
                if (node.callee.type === "Super" && isBeforeCallOfSuper()) {
                    setSuperCalled();
                }
            },
 
            /**
             * Resets state.
             * @returns {void}
             */
            "Program:exit"() {
                segInfoMap = Object.create(null);
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-throw-literal.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-throw-literal.js

Statements: 25% (2 / 8)      Branches: 0% (0 / 6)      Functions: 0% (0 / 2)      Lines: 25% (2 / 8)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45              1           1                                                              
/**
 * @fileoverview Rule to restrict what can be thrown as an exception.
 * @author Dieter Oberkofler
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow throwing literals as exceptions",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
 
            ThrowStatement(node) {
                if (!astUtils.couldBeError(node.argument)) {
                    context.report({ node, message: "Expected an object to be thrown." });
                } else if (node.argument.type === "Identifier") {
                    if (node.argument.name === "undefined") {
                        context.report({ node, message: "Do not throw undefined." });
                    }
                }
 
            }
 
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-trailing-spaces.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-trailing-spaces.js

Statements: 10.34% (3 / 29)      Branches: 0% (0 / 20)      Functions: 0% (0 / 4)      Lines: 10.34% (3 / 29)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139                    1           1                                                                               1                                                                                                                                                                    
/**
 * @fileoverview Disallow trailing spaces at the end of lines.
 * @author Nodeca Team <https://github.com/nodeca>
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow trailing whitespace at the end of lines",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                type: "object",
                properties: {
                    skipBlankLines: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        const BLANK_CLASS = "[ \t\u00a0\u2000-\u200b\u3000]",
            SKIP_BLANK = `^${BLANK_CLASS}*$`,
            NONBLANK = `${BLANK_CLASS}+$`;
 
        const options = context.options[0] || {},
            skipBlankLines = options.skipBlankLines || false;
 
        /**
         * Report the error message
         * @param {ASTNode} node node to report
         * @param {int[]} location range information
         * @param {int[]} fixRange Range based on the whole program
         * @returns {void}
         */
        function report(node, location, fixRange) {
 
            /*
             * Passing node is a bit dirty, because message data will contain big
             * text in `source`. But... who cares :) ?
             * One more kludge will not make worse the bloody wizardry of this
             * plugin.
             */
            context.report({
                node,
                loc: location,
                message: "Trailing spaces not allowed.",
                fix(fixer) {
                    return fixer.removeRange(fixRange);
                }
            });
        }
 
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
 
            Program: function checkTrailingSpaces(node) {
 
                // Let's hack. Since Espree does not return whitespace nodes,
                // fetch the source code and do matching via regexps.
 
                const re = new RegExp(NONBLANK),
                    skipMatch = new RegExp(SKIP_BLANK),
                    lines = sourceCode.lines,
                    linebreaks = sourceCode.getText().match(astUtils.createGlobalLinebreakMatcher());
                let totalLength = 0,
                    fixRange = [];
 
                for (let i = 0, ii = lines.length; i < ii; i++) {
                    const matches = re.exec(lines[i]);
 
                    // Always add linebreak length to line length to accommodate for line break (\n or \r\n)
                    // Because during the fix time they also reserve one spot in the array.
                    // Usually linebreak length is 2 for \r\n (CRLF) and 1 for \n (LF)
                    const linebreakLength = linebreaks && linebreaks[i] ? linebreaks[i].length : 1;
                    const lineLength = lines[i].length + linebreakLength;
 
                    if (matches) {
                        const location = {
                            line: i + 1,
                            column: matches.index
                        };
 
                        const rangeStart = totalLength + location.column;
                        const rangeEnd = totalLength + lineLength - linebreakLength;
                        const containingNode = sourceCode.getNodeByRangeIndex(rangeStart);
 
                        if (containingNode && containingNode.type === "TemplateElement" &&
                          rangeStart > containingNode.parent.range[0] &&
                          rangeEnd < containingNode.parent.range[1]) {
                            totalLength += lineLength;
                            continue;
                        }
 
                        // If the line has only whitespace, and skipBlankLines
                        // is true, don't report it
                        if (skipBlankLines && skipMatch.test(lines[i])) {
                            totalLength += lineLength;
                            continue;
                        }
 
                        fixRange = [rangeStart, rangeEnd];
                        report(node, location, fixRange);
                    }
 
                    totalLength += lineLength;
                }
            }
 
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-undef-init.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-undef-init.js

Statements: 20% (2 / 10)      Branches: 0% (0 / 13)      Functions: 0% (0 / 3)      Lines: 20% (2 / 10)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61              1           1                                                                                              
/**
 * @fileoverview Rule to flag when initializing to undefined
 * @author Ilya Volodin
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow initializing variables to `undefined`",
            category: "Variables",
            recommended: false
        },
 
        schema: [],
 
        fixable: "code"
    },
 
    create(context) {
 
        const sourceCode = context.getSourceCode();
 
        return {
 
            VariableDeclarator(node) {
                const name = sourceCode.getText(node.id),
                    init = node.init && node.init.name,
                    scope = context.getScope(),
                    undefinedVar = astUtils.getVariableByName(scope, "undefined"),
                    shadowed = undefinedVar && undefinedVar.defs.length > 0;
 
                if (init === "undefined" && node.parent.kind !== "const" && !shadowed) {
                    context.report({
                        node,
                        message: "It's not necessary to initialize '{{name}}' to undefined.",
                        data: { name },
                        fix(fixer) {
                            if (node.id.type === "ArrayPattern" || node.id.type === "ObjectPattern") {
 
                                // Don't fix destructuring assignment to `undefined`.
                                return null;
                            }
                            return fixer.removeRange([node.id.range[1], node.range[1]]);
                        }
                    });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-undef.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-undef.js

Statements: 15.38% (2 / 13)      Branches: 0% (0 / 9)      Functions: 0% (0 / 3)      Lines: 15.38% (2 / 13)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73                              1                   1                                                                                              
/**
 * @fileoverview Rule to flag references to undeclared variables.
 * @author Mark Macdonald
 */
"use strict";
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks if the given node is the argument of a typeof operator.
 * @param {ASTNode} node The AST node being checked.
 * @returns {boolean} Whether or not the node is the argument of a typeof operator.
 */
function hasTypeOfOperator(node) {
    const parent = node.parent;
 
    return parent.type === "UnaryExpression" && parent.operator === "typeof";
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow the use of undeclared variables unless mentioned in `/*global */` comments",
            category: "Variables",
            recommended: true
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    typeof: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const options = context.options[0];
        const considerTypeOf = options && options.typeof === true || false;
 
        return {
            "Program:exit"(/* node */) {
                const globalScope = context.getScope();
 
                globalScope.through.forEach(ref => {
                    const identifier = ref.identifier;
 
                    if (!considerTypeOf && hasTypeOfOperator(identifier)) {
                        return;
                    }
 
                    context.report({
                        node: identifier,
                        message: "'{{name}}' is not defined.",
                        data: identifier
                    });
                });
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-undefined.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-undefined.js

Statements: 14.29% (3 / 21)      Branches: 0% (0 / 2)      Functions: 0% (0 / 4)      Lines: 15% (3 / 20)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79                    1                                   1                         1                                                                          
/**
 * @fileoverview Rule to flag references to the undefined variable.
 * @author Michael Ficarra
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow the use of `undefined` as an identifier",
            category: "Variables",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        /**
         * Report an invalid "undefined" identifier node.
         * @param {ASTNode} node The node to report.
         * @returns {void}
         */
        function report(node) {
            context.report({
                node,
                message: "Unexpected use of undefined."
            });
        }
 
        /**
         * Checks the given scope for references to `undefined` and reports
         * all references found.
         * @param {escope.Scope} scope The scope to check.
         * @returns {void}
         */
        function checkScope(scope) {
            const undefinedVar = scope.set.get("undefined");
 
            if (!undefinedVar) {
                return;
            }
 
            const references = undefinedVar.references;
 
            const defs = undefinedVar.defs;
 
            // Report non-initializing references (those are covered in defs below)
            references
                .filter(ref => !ref.init)
                .forEach(ref => report(ref.identifier));
 
            defs.forEach(def => report(def.name));
        }
 
        return {
            "Program:exit"() {
                const globalScope = context.getScope();
 
                const stack = [globalScope];
 
                while (stack.length) {
                    const scope = stack.pop();
 
                    stack.push.apply(stack, scope.childScopes);
                    checkScope(scope);
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-underscore-dangle.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-underscore-dangle.js

Statements: 27.59% (8 / 29)      Branches: 0% (0 / 36)      Functions: 0% (0 / 8)      Lines: 28.57% (8 / 28)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178                      1                                                                                             1                   1                       1                   1                       1                                           1                                         1                                                                
/**
 * @fileoverview Rule to flag trailing underscores in variable declarations.
 * @author Matt DuVall <http://www.mattduvall.com>
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow dangling underscores in identifiers",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    allow: {
                        type: "array",
                        items: {
                            type: "string"
                        }
                    },
                    allowAfterThis: {
                        type: "boolean"
                    },
                    allowAfterSuper: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        const options = context.options[0] || {};
        const ALLOWED_VARIABLES = options.allow ? options.allow : [];
        const allowAfterThis = typeof options.allowAfterThis !== "undefined" ? options.allowAfterThis : false;
        const allowAfterSuper = typeof options.allowAfterSuper !== "undefined" ? options.allowAfterSuper : false;
 
        //-------------------------------------------------------------------------
        // Helpers
        //-------------------------------------------------------------------------
 
        /**
         * Check if identifier is present inside the allowed option
         * @param {string} identifier name of the node
         * @returns {boolean} true if its is present
         * @private
         */
        function isAllowed(identifier) {
            return ALLOWED_VARIABLES.some(ident => ident === identifier);
        }
 
        /**
         * Check if identifier has a underscore at the end
         * @param {ASTNode} identifier node to evaluate
         * @returns {boolean} true if its is present
         * @private
         */
        function hasTrailingUnderscore(identifier) {
            const len = identifier.length;
 
            return identifier !== "_" && (identifier[0] === "_" || identifier[len - 1] === "_");
        }
 
        /**
         * Check if identifier is a special case member expression
         * @param {ASTNode} identifier node to evaluate
         * @returns {boolean} true if its is a special case
         * @private
         */
        function isSpecialCaseIdentifierForMemberExpression(identifier) {
            return identifier === "__proto__";
        }
 
        /**
         * Check if identifier is a special case variable expression
         * @param {ASTNode} identifier node to evaluate
         * @returns {boolean} true if its is a special case
         * @private
         */
        function isSpecialCaseIdentifierInVariableExpression(identifier) {
 
            // Checks for the underscore library usage here
            return identifier === "_";
        }
 
        /**
         * Check if function has a underscore at the end
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function checkForTrailingUnderscoreInFunctionDeclaration(node) {
            if (node.id) {
                const identifier = node.id.name;
 
                if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) && !isAllowed(identifier)) {
                    context.report({
                        node,
                        message: "Unexpected dangling '_' in '{{identifier}}'.",
                        data: {
                            identifier
                        }
                    });
                }
            }
        }
 
        /**
         * Check if variable expression has a underscore at the end
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function checkForTrailingUnderscoreInVariableExpression(node) {
            const identifier = node.id.name;
 
            if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) &&
                !isSpecialCaseIdentifierInVariableExpression(identifier) && !isAllowed(identifier)) {
                context.report({
                    node,
                    message: "Unexpected dangling '_' in '{{identifier}}'.",
                    data: {
                        identifier
                    }
                });
            }
        }
 
        /**
         * Check if member expression has a underscore at the end
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function checkForTrailingUnderscoreInMemberExpression(node) {
            const identifier = node.property.name,
                isMemberOfThis = node.object.type === "ThisExpression",
                isMemberOfSuper = node.object.type === "Super";
 
            if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) &&
                !(isMemberOfThis && allowAfterThis) &&
                !(isMemberOfSuper && allowAfterSuper) &&
                !isSpecialCaseIdentifierForMemberExpression(identifier) && !isAllowed(identifier)) {
                context.report({
                    node,
                    message: "Unexpected dangling '_' in '{{identifier}}'.",
                    data: {
                        identifier
                    }
                });
            }
        }
 
        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------
 
        return {
            FunctionDeclaration: checkForTrailingUnderscoreInFunctionDeclaration,
            VariableDeclarator: checkForTrailingUnderscoreInVariableExpression,
            MemberExpression: checkForTrailingUnderscoreInMemberExpression
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-unexpected-multiline.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-unexpected-multiline.js

Statements: 14.29% (3 / 21)      Branches: 0% (0 / 8)      Functions: 0% (0 / 5)      Lines: 14.29% (3 / 21)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84                    1           1                                                     1                                                                                
/**
 * @fileoverview Rule to spot scenarios where a newline looks like it is ending a statement, but is not.
 * @author Glen Mailer
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow confusing multiline expressions",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
 
        const FUNCTION_MESSAGE = "Unexpected newline between function and ( of function call.";
        const PROPERTY_MESSAGE = "Unexpected newline between object and [ of property access.";
        const TAGGED_TEMPLATE_MESSAGE = "Unexpected newline between template tag and template literal.";
 
        const sourceCode = context.getSourceCode();
 
        /**
         * Check to see if there is a newline between the node and the following open bracket
         * line's expression
         * @param {ASTNode} node The node to check.
         * @param {string} msg The error message to use.
         * @returns {void}
         * @private
         */
        function checkForBreakAfter(node, msg) {
            const openParen = sourceCode.getTokenAfter(node, astUtils.isNotClosingParenToken);
            const nodeExpressionEnd = sourceCode.getTokenBefore(openParen);
 
            if (openParen.loc.start.line !== nodeExpressionEnd.loc.end.line) {
                context.report({ node, loc: openParen.loc.start, message: msg, data: { char: openParen.value } });
            }
        }
 
        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------
 
        return {
 
            MemberExpression(node) {
                if (!node.computed) {
                    return;
                }
                checkForBreakAfter(node.object, PROPERTY_MESSAGE);
            },
 
            TaggedTemplateExpression(node) {
                if (node.tag.loc.end.line === node.quasi.loc.start.line) {
                    return;
                }
                context.report({ node, loc: node.loc.start, message: TAGGED_TEMPLATE_MESSAGE });
            },
 
            CallExpression(node) {
                if (node.arguments.length === 0) {
                    return;
                }
                checkForBreakAfter(node.callee, FUNCTION_MESSAGE);
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-unmodified-loop-condition.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-unmodified-loop-condition.js

Statements: 20.79% (21 / 101)      Branches: 0% (0 / 54)      Functions: 0% (0 / 16)      Lines: 20.79% (21 / 101)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368                      1             1 1 1 1 1 1                                     1                                   1                     1                     1                             1                                   1                                               1                                                                                                           1                                         1                                                           1                                       1                                 1                                           1                         1                                                                                                      
/**
 * @fileoverview Rule to disallow use of unmodified expressions in loop conditions
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const Traverser = require("../util/traverser"),
    astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const pushAll = Function.apply.bind(Array.prototype.push);
const SENTINEL_PATTERN = /(?:(?:Call|Class|Function|Member|New|Yield)Expression|Statement|Declaration)$/;
const LOOP_PATTERN = /^(?:DoWhile|For|While)Statement$/;  // for-in/of statements don't have `test` property.
const GROUP_PATTERN = /^(?:BinaryExpression|ConditionalExpression)$/;
const SKIP_PATTERN = /^(?:ArrowFunction|Class|Function)Expression$/;
const DYNAMIC_PATTERN = /^(?:Call|Member|New|TaggedTemplate|Yield)Expression$/;
 
/**
 * @typedef {Object} LoopConditionInfo
 * @property {escope.Reference} reference - The reference.
 * @property {ASTNode} group - BinaryExpression or ConditionalExpression nodes
 *      that the reference is belonging to.
 * @property {Function} isInLoop - The predicate which checks a given reference
 *      is in this loop.
 * @property {boolean} modified - The flag that the reference is modified in
 *      this loop.
 */
 
/**
 * Checks whether or not a given reference is a write reference.
 *
 * @param {escope.Reference} reference - A reference to check.
 * @returns {boolean} `true` if the reference is a write reference.
 */
function isWriteReference(reference) {
    if (reference.init) {
        const def = reference.resolved && reference.resolved.defs[0];
 
        if (!def || def.type !== "Variable" || def.parent.kind !== "var") {
            return false;
        }
    }
    return reference.isWrite();
}
 
/**
 * Checks whether or not a given loop condition info does not have the modified
 * flag.
 *
 * @param {LoopConditionInfo} condition - A loop condition info to check.
 * @returns {boolean} `true` if the loop condition info is "unmodified".
 */
function isUnmodified(condition) {
    return !condition.modified;
}
 
/**
 * Checks whether or not a given loop condition info does not have the modified
 * flag and does not have the group this condition belongs to.
 *
 * @param {LoopConditionInfo} condition - A loop condition info to check.
 * @returns {boolean} `true` if the loop condition info is "unmodified".
 */
function isUnmodifiedAndNotBelongToGroup(condition) {
    return !(condition.modified || condition.group);
}
 
/**
 * Checks whether or not a given reference is inside of a given node.
 *
 * @param {ASTNode} node - A node to check.
 * @param {escope.Reference} reference - A reference to check.
 * @returns {boolean} `true` if the reference is inside of the node.
 */
function isInRange(node, reference) {
    const or = node.range;
    const ir = reference.identifier.range;
 
    return or[0] <= ir[0] && ir[1] <= or[1];
}
 
/**
 * Checks whether or not a given reference is inside of a loop node's condition.
 *
 * @param {ASTNode} node - A node to check.
 * @param {escope.Reference} reference - A reference to check.
 * @returns {boolean} `true` if the reference is inside of the loop node's
 *      condition.
 */
const isInLoop = {
    WhileStatement: isInRange,
    DoWhileStatement: isInRange,
    ForStatement(node, reference) {
        return (
            isInRange(node, reference) &&
            !(node.init && isInRange(node.init, reference))
        );
    }
};
 
/**
 * Checks whether or not a given group node has any dynamic elements.
 *
 * @param {ASTNode} root - A node to check.
 *      This node is one of BinaryExpression or ConditionalExpression.
 * @returns {boolean} `true` if the node is dynamic.
 */
function hasDynamicExpressions(root) {
    let retv = false;
    const traverser = new Traverser();
 
    traverser.traverse(root, {
        enter(node) {
            if (DYNAMIC_PATTERN.test(node.type)) {
                retv = true;
                this.break();
            } else if (SKIP_PATTERN.test(node.type)) {
                this.skip();
            }
        }
    });
 
    return retv;
}
 
/**
 * Creates the loop condition information from a given reference.
 *
 * @param {escope.Reference} reference - A reference to create.
 * @returns {LoopConditionInfo|null} Created loop condition info, or null.
 */
function toLoopCondition(reference) {
    if (reference.init) {
        return null;
    }
 
    let group = null;
    let child = reference.identifier;
    let node = child.parent;
 
    while (node) {
        if (SENTINEL_PATTERN.test(node.type)) {
            if (LOOP_PATTERN.test(node.type) && node.test === child) {
 
                // This reference is inside of a loop condition.
                return {
                    reference,
                    group,
                    isInLoop: isInLoop[node.type].bind(null, node),
                    modified: false
                };
            }
 
            // This reference is outside of a loop condition.
            break;
        }
 
        /*
         * If it's inside of a group, OK if either operand is modified.
         * So stores the group this reference belongs to.
         */
        if (GROUP_PATTERN.test(node.type)) {
 
            // If this expression is dynamic, no need to check.
            if (hasDynamicExpressions(node)) {
                break;
            } else {
                group = node;
            }
        }
 
        child = node;
        node = node.parent;
    }
 
    return null;
}
 
/**
 * Gets the function which encloses a given reference.
 * This supports only FunctionDeclaration.
 *
 * @param {escope.Reference} reference - A reference to get.
 * @returns {ASTNode|null} The function node or null.
 */
function getEncloseFunctionDeclaration(reference) {
    let node = reference.identifier;
 
    while (node) {
        if (node.type === "FunctionDeclaration") {
            return node.id ? node : null;
        }
 
        node = node.parent;
    }
 
    return null;
}
 
/**
 * Updates the "modified" flags of given loop conditions with given modifiers.
 *
 * @param {LoopConditionInfo[]} conditions - The loop conditions to be updated.
 * @param {escope.Reference[]} modifiers - The references to update.
 * @returns {void}
 */
function updateModifiedFlag(conditions, modifiers) {
    let funcNode, funcVar;
 
    for (let i = 0; i < conditions.length; ++i) {
        const condition = conditions[i];
 
        for (let j = 0; !condition.modified && j < modifiers.length; ++j) {
            const modifier = modifiers[j];
 
            /*
             * Besides checking for the condition being in the loop, we want to
             * check the function that this modifier is belonging to is called
             * in the loop.
             * FIXME: This should probably be extracted to a function.
             */
            const inLoop = condition.isInLoop(modifier) || Boolean(
                (funcNode = getEncloseFunctionDeclaration(modifier)) &&
                (funcVar = astUtils.getVariableByName(modifier.from.upper, funcNode.id.name)) &&
                funcVar.references.some(condition.isInLoop)
            );
 
            condition.modified = inLoop;
        }
    }
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow unmodified loop conditions",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
        let groupMap = null;
 
        /**
         * Reports a given condition info.
         *
         * @param {LoopConditionInfo} condition - A loop condition info to report.
         * @returns {void}
         */
        function report(condition) {
            const node = condition.reference.identifier;
 
            context.report({
                node,
                message: "'{{name}}' is not modified in this loop.",
                data: node
            });
        }
 
        /**
         * Registers given conditions to the group the condition belongs to.
         *
         * @param {LoopConditionInfo[]} conditions - A loop condition info to
         *      register.
         * @returns {void}
         */
        function registerConditionsToGroup(conditions) {
            for (let i = 0; i < conditions.length; ++i) {
                const condition = conditions[i];
 
                if (condition.group) {
                    let group = groupMap.get(condition.group);
 
                    if (!group) {
                        group = [];
                        groupMap.set(condition.group, group);
                    }
                    group.push(condition);
                }
            }
        }
 
        /**
         * Reports references which are inside of unmodified groups.
         *
         * @param {LoopConditionInfo[]} conditions - A loop condition info to report.
         * @returns {void}
         */
        function checkConditionsInGroup(conditions) {
            if (conditions.every(isUnmodified)) {
                conditions.forEach(report);
            }
        }
 
        /**
         * Finds unmodified references which are inside of a loop condition.
         * Then reports the references which are outside of groups.
         *
         * @param {escope.Variable} variable - A variable to report.
         * @returns {void}
         */
        function checkReferences(variable) {
 
            // Gets references that exist in loop conditions.
            const conditions = variable
                .references
                .map(toLoopCondition)
                .filter(Boolean);
 
            if (conditions.length === 0) {
                return;
            }
 
            // Registers the conditions to belonging groups.
            registerConditionsToGroup(conditions);
 
            // Check the conditions are modified.
            const modifiers = variable.references.filter(isWriteReference);
 
            if (modifiers.length > 0) {
                updateModifiedFlag(conditions, modifiers);
            }
 
            /*
             * Reports the conditions which are not belonging to groups.
             * Others will be reported after all variables are done.
             */
            conditions
                .filter(isUnmodifiedAndNotBelongToGroup)
                .forEach(report);
        }
 
        return {
            "Program:exit"() {
                const queue = [context.getScope()];
 
                groupMap = new Map();
 
                let scope;
 
                while ((scope = queue.pop())) {
                    pushAll(queue, scope.childScopes);
                    scope.variables.forEach(checkReferences);
                }
 
                groupMap.forEach(checkConditionsInGroup);
                groupMap = null;
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-unneeded-ternary.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-unneeded-ternary.js

Statements: 25% (8 / 32)      Branches: 0% (0 / 33)      Functions: 0% (0 / 7)      Lines: 25% (8 / 32)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145              1     1 1                         1                                                                   1                 1                                           1                     1                                                                                        
/**
 * @fileoverview Rule to flag no-unneeded-ternary
 * @author Gyandeep Singh
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
// Operators that always result in a boolean value
const BOOLEAN_OPERATORS = new Set(["==", "===", "!=", "!==", ">", ">=", "<", "<=", "in", "instanceof"]);
const OPERATOR_INVERSES = {
    "==": "!=",
    "!=": "==",
    "===": "!==",
    "!==": "==="
 
    // Operators like < and >= are not true inverses, since both will return false with NaN.
};
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow ternary operators when simpler alternatives exist",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    defaultAssignment: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ],
 
        fixable: "code"
    },
 
    create(context) {
        const options = context.options[0] || {};
        const defaultAssignment = options.defaultAssignment !== false;
        const sourceCode = context.getSourceCode();
 
        /**
         * Test if the node is a boolean literal
         * @param {ASTNode} node - The node to report.
         * @returns {boolean} True if the its a boolean literal
         * @private
         */
        function isBooleanLiteral(node) {
            return node.type === "Literal" && typeof node.value === "boolean";
        }
 
        /**
         * Creates an expression that represents the boolean inverse of the expression represented by the original node
         * @param {ASTNode} node A node representing an expression
         * @returns {string} A string representing an inverted expression
         */
        function invertExpression(node) {
            if (node.type === "BinaryExpression" && Object.prototype.hasOwnProperty.call(OPERATOR_INVERSES, node.operator)) {
                const operatorToken = sourceCode.getFirstTokenBetween(
                    node.left,
                    node.right,
                    token => token.value === node.operator
                );
 
                return sourceCode.getText().slice(node.range[0], operatorToken.range[0]) + OPERATOR_INVERSES[node.operator] + sourceCode.getText().slice(operatorToken.range[1], node.range[1]);
            }
 
            if (astUtils.getPrecedence(node) < astUtils.getPrecedence({ type: "UnaryExpression" })) {
                return `!(${astUtils.getParenthesisedText(sourceCode, node)})`;
            }
            return `!${astUtils.getParenthesisedText(sourceCode, node)}`;
        }
 
        /**
         * Tests if a given node always evaluates to a boolean value
         * @param {ASTNode} node - An expression node
         * @returns {boolean} True if it is determined that the node will always evaluate to a boolean value
         */
        function isBooleanExpression(node) {
            return node.type === "BinaryExpression" && BOOLEAN_OPERATORS.has(node.operator) ||
                node.type === "UnaryExpression" && node.operator === "!";
        }
 
        /**
         * Test if the node matches the pattern id ? id : expression
         * @param {ASTNode} node - The ConditionalExpression to check.
         * @returns {boolean} True if the pattern is matched, and false otherwise
         * @private
         */
        function matchesDefaultAssignment(node) {
            return node.test.type === "Identifier" &&
                   node.consequent.type === "Identifier" &&
                   node.test.name === node.consequent.name;
        }
 
        return {
 
            ConditionalExpression(node) {
                if (isBooleanLiteral(node.alternate) && isBooleanLiteral(node.consequent)) {
                    context.report({
                        node,
                        loc: node.consequent.loc.start,
                        message: "Unnecessary use of boolean literals in conditional expression.",
                        fix(fixer) {
                            if (node.consequent.value === node.alternate.value) {
 
                                // Replace `foo ? true : true` with just `true`, but don't replace `foo() ? true : true`
                                return node.test.type === "Identifier" ? fixer.replaceText(node, node.consequent.value.toString()) : null;
                            }
                            if (node.alternate.value) {
 
                                // Replace `foo() ? false : true` with `!(foo())`
                                return fixer.replaceText(node, invertExpression(node.test));
                            }
 
                            // Replace `foo ? true : false` with `foo` if `foo` is guaranteed to be a boolean, or `!!foo` otherwise.
 
                            return fixer.replaceText(node, isBooleanExpression(node.test) ? astUtils.getParenthesisedText(sourceCode, node.test) : `!${invertExpression(node.test)}`);
                        }
                    });
                } else if (!defaultAssignment && matchesDefaultAssignment(node)) {
                    context.report({
                        node,
                        loc: node.consequent.loc.start,
                        message: "Unnecessary use of conditional expression for default assignment.",
                        fix: fixer => fixer.replaceText(node, `${astUtils.getParenthesisedText(sourceCode, node.test)} || ${astUtils.getParenthesisedText(sourceCode, node.alternate)}`)
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-unreachable.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-unreachable.js

Statements: 10.81% (4 / 37)      Branches: 0% (0 / 20)      Functions: 0% (0 / 15)      Lines: 10.81% (4 / 37)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212                              1                 1                                                                                                                                                         1                                         1                                                                                                                                                                                  
/**
 * @fileoverview Checks for unreachable code due to return, throws, break, and continue.
 * @author Joel Feenstra
 */
"use strict";
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks whether or not a given variable declarator has the initializer.
 * @param {ASTNode} node - A VariableDeclarator node to check.
 * @returns {boolean} `true` if the node has the initializer.
 */
function isInitialized(node) {
    return Boolean(node.init);
}
 
/**
 * Checks whether or not a given code path segment is unreachable.
 * @param {CodePathSegment} segment - A CodePathSegment to check.
 * @returns {boolean} `true` if the segment is unreachable.
 */
function isUnreachable(segment) {
    return !segment.reachable;
}
 
/**
 * The class to distinguish consecutive unreachable statements.
 */
class ConsecutiveRange {
    constructor(sourceCode) {
        this.sourceCode = sourceCode;
        this.startNode = null;
        this.endNode = null;
    }
 
    /**
     * The location object of this range.
     * @type {Object}
     */
    get location() {
        return {
            start: this.startNode.loc.start,
            end: this.endNode.loc.end
        };
    }
 
    /**
     * `true` if this range is empty.
     * @type {boolean}
     */
    get isEmpty() {
        return !(this.startNode && this.endNode);
    }
 
    /**
     * Checks whether the given node is inside of this range.
     * @param {ASTNode|Token} node - The node to check.
     * @returns {boolean} `true` if the node is inside of this range.
     */
    contains(node) {
        return (
            node.range[0] >= this.startNode.range[0] &&
            node.range[1] <= this.endNode.range[1]
        );
    }
 
    /**
     * Checks whether the given node is consecutive to this range.
     * @param {ASTNode} node - The node to check.
     * @returns {boolean} `true` if the node is consecutive to this range.
     */
    isConsecutive(node) {
        return this.contains(this.sourceCode.getTokenBefore(node));
    }
 
    /**
     * Merges the given node to this range.
     * @param {ASTNode} node - The node to merge.
     * @returns {void}
     */
    merge(node) {
        this.endNode = node;
    }
 
    /**
     * Resets this range by the given node or null.
     * @param {ASTNode|null} node - The node to reset, or null.
     * @returns {void}
     */
    reset(node) {
        this.startNode = this.endNode = node;
    }
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow unreachable code after `return`, `throw`, `continue`, and `break` statements",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
        let currentCodePath = null;
 
        const range = new ConsecutiveRange(context.getSourceCode());
 
        /**
         * Reports a given node if it's unreachable.
         * @param {ASTNode} node - A statement node to report.
         * @returns {void}
         */
        function reportIfUnreachable(node) {
            let nextNode = null;
 
            if (node && currentCodePath.currentSegments.every(isUnreachable)) {
 
                // Store this statement to distinguish consecutive statements.
                if (range.isEmpty) {
                    range.reset(node);
                    return;
                }
 
                // Skip if this statement is inside of the current range.
                if (range.contains(node)) {
                    return;
                }
 
                // Merge if this statement is consecutive to the current range.
                if (range.isConsecutive(node)) {
                    range.merge(node);
                    return;
                }
 
                nextNode = node;
            }
 
            // Report the current range since this statement is reachable or is
            // not consecutive to the current range.
            if (!range.isEmpty) {
                context.report({
                    message: "Unreachable code.",
                    loc: range.location,
                    node: range.startNode
                });
            }
 
            // Update the current range.
            range.reset(nextNode);
        }
 
        return {
 
            // Manages the current code path.
            onCodePathStart(codePath) {
                currentCodePath = codePath;
            },
 
            onCodePathEnd() {
                currentCodePath = currentCodePath.upper;
            },
 
            // Registers for all statement nodes (excludes FunctionDeclaration).
            BlockStatement: reportIfUnreachable,
            BreakStatement: reportIfUnreachable,
            ClassDeclaration: reportIfUnreachable,
            ContinueStatement: reportIfUnreachable,
            DebuggerStatement: reportIfUnreachable,
            DoWhileStatement: reportIfUnreachable,
            EmptyStatement: reportIfUnreachable,
            ExpressionStatement: reportIfUnreachable,
            ForInStatement: reportIfUnreachable,
            ForOfStatement: reportIfUnreachable,
            ForStatement: reportIfUnreachable,
            IfStatement: reportIfUnreachable,
            ImportDeclaration: reportIfUnreachable,
            LabeledStatement: reportIfUnreachable,
            ReturnStatement: reportIfUnreachable,
            SwitchStatement: reportIfUnreachable,
            ThrowStatement: reportIfUnreachable,
            TryStatement: reportIfUnreachable,
 
            VariableDeclaration(node) {
                if (node.kind !== "var" || node.declarations.some(isInitialized)) {
                    reportIfUnreachable(node);
                }
            },
 
            WhileStatement: reportIfUnreachable,
            WithStatement: reportIfUnreachable,
            ExportNamedDeclaration: reportIfUnreachable,
            ExportDefaultDeclaration: reportIfUnreachable,
            ExportAllDeclaration: reportIfUnreachable,
 
            "Program:exit"() {
                reportIfUnreachable();
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-unsafe-finally.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-unsafe-finally.js

Statements: 25.93% (7 / 27)      Branches: 0% (0 / 23)      Functions: 0% (0 / 4)      Lines: 25.93% (7 / 27)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106                      1 1 1             1                                   1                     1                                                                 1                                              
/**
 * @fileoverview Rule to flag unsafe statements in finally block
 * @author Onur Temizkan
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const SENTINEL_NODE_TYPE_RETURN_THROW = /^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression)$/;
const SENTINEL_NODE_TYPE_BREAK = /^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|DoWhileStatement|WhileStatement|ForOfStatement|ForInStatement|ForStatement|SwitchStatement)$/;
const SENTINEL_NODE_TYPE_CONTINUE = /^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|DoWhileStatement|WhileStatement|ForOfStatement|ForInStatement|ForStatement)$/;
 
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow control flow statements in `finally` blocks",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: []
    },
    create(context) {
 
        /**
         * Checks if the node is the finalizer of a TryStatement
         *
         * @param {ASTNode} node - node to check.
         * @returns {boolean} - true if the node is the finalizer of a TryStatement
         */
        function isFinallyBlock(node) {
            return node.parent.type === "TryStatement" && node.parent.finalizer === node;
        }
 
        /**
         * Climbs up the tree if the node is not a sentinel node
         *
         * @param {ASTNode} node - node to check.
         * @param {string} label - label of the break or continue statement
         * @returns {boolean} - return whether the node is a finally block or a sentinel node
         */
        function isInFinallyBlock(node, label) {
            let labelInside = false;
            let sentinelNodeType;
 
            if (node.type === "BreakStatement" && !node.label) {
                sentinelNodeType = SENTINEL_NODE_TYPE_BREAK;
            } else if (node.type === "ContinueStatement") {
                sentinelNodeType = SENTINEL_NODE_TYPE_CONTINUE;
            } else {
                sentinelNodeType = SENTINEL_NODE_TYPE_RETURN_THROW;
            }
 
            while (node && !sentinelNodeType.test(node.type)) {
                if (node.parent.label && label && (node.parent.label.name === label.name)) {
                    labelInside = true;
                }
                if (isFinallyBlock(node)) {
                    if (label && labelInside) {
                        return false;
                    }
                    return true;
                }
                node = node.parent;
            }
            return false;
        }
 
        /**
         * Checks whether the possibly-unsafe statement is inside a finally block.
         *
         * @param {ASTNode} node - node to check.
         * @returns {void}
         */
        function check(node) {
            if (isInFinallyBlock(node, node.label)) {
                context.report({
                    message: "Unsafe usage of {{nodeType}}.",
                    data: {
                        nodeType: node.type
                    },
                    node,
                    line: node.loc.line,
                    column: node.loc.column
                });
            }
        }
 
        return {
            ReturnStatement: check,
            ThrowStatement: check,
            BreakStatement: check,
            ContinueStatement: check
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-unsafe-negation.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-unsafe-negation.js

Statements: 28.57% (4 / 14)      Branches: 0% (0 / 9)      Functions: 0% (0 / 5)      Lines: 28.57% (4 / 14)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82                      1                       1                   1               1                                                                                
/**
 * @fileoverview Rule to disallow negating the left operand of relational operators
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks whether the given operator is a relational operator or not.
 *
 * @param {string} op - The operator type to check.
 * @returns {boolean} `true` if the operator is a relational operator.
 */
function isRelationalOperator(op) {
    return op === "in" || op === "instanceof";
}
 
/**
 * Checks whether the given node is a logical negation expression or not.
 *
 * @param {ASTNode} node - The node to check.
 * @returns {boolean} `true` if the node is a logical negation expression.
 */
function isNegation(node) {
    return node.type === "UnaryExpression" && node.operator === "!";
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow negating the left operand of relational operators",
            category: "Possible Errors",
            recommended: true
        },
        schema: [],
        fixable: "code"
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        return {
            BinaryExpression(node) {
                if (isRelationalOperator(node.operator) &&
                    isNegation(node.left) &&
                    !astUtils.isParenthesised(sourceCode, node.left)
                ) {
                    context.report({
                        node,
                        loc: node.left.loc,
                        message: "Unexpected negating the left operand of '{{operator}}' operator.",
                        data: node,
 
                        fix(fixer) {
                            const negationToken = sourceCode.getFirstToken(node.left);
                            const fixRange = [negationToken.range[1], node.range[1]];
                            const text = sourceCode.text.slice(fixRange[0], fixRange[1]);
 
                            return fixer.replaceTextRange(fixRange, `(${text})`);
                        }
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-unused-expressions.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-unused-expressions.js

Statements: 22.22% (6 / 27)      Branches: 0% (0 / 38)      Functions: 0% (0 / 7)      Lines: 22.22% (6 / 27)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128                    1                                                                         1                   1                         1                 1                           1                                                                    
/**
 * @fileoverview Flag expressions in statement position that do not side effect
 * @author Michael Ficarra
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow unused expressions",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    allowShortCircuit: {
                        type: "boolean"
                    },
                    allowTernary: {
                        type: "boolean"
                    },
                    allowTaggedTemplates: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const config = context.options[0] || {},
            allowShortCircuit = config.allowShortCircuit || false,
            allowTernary = config.allowTernary || false,
            allowTaggedTemplates = config.allowTaggedTemplates || false;
 
        /**
         * @param {ASTNode} node - any node
         * @returns {boolean} whether the given node structurally represents a directive
         */
        function looksLikeDirective(node) {
            return node.type === "ExpressionStatement" &&
                node.expression.type === "Literal" && typeof node.expression.value === "string";
        }
 
        /**
         * @param {Function} predicate - ([a] -> Boolean) the function used to make the determination
         * @param {a[]} list - the input list
         * @returns {a[]} the leading sequence of members in the given list that pass the given predicate
         */
        function takeWhile(predicate, list) {
            for (let i = 0; i < list.length; ++i) {
                if (!predicate(list[i])) {
                    return list.slice(0, i);
                }
            }
            return list.slice();
        }
 
        /**
         * @param {ASTNode} node - a Program or BlockStatement node
         * @returns {ASTNode[]} the leading sequence of directive nodes in the given node's body
         */
        function directives(node) {
            return takeWhile(looksLikeDirective, node.body);
        }
 
        /**
         * @param {ASTNode} node - any node
         * @param {ASTNode[]} ancestors - the given node's ancestors
         * @returns {boolean} whether the given node is considered a directive in its current position
         */
        function isDirective(node, ancestors) {
            const parent = ancestors[ancestors.length - 1],
                grandparent = ancestors[ancestors.length - 2];
 
            return (parent.type === "Program" || parent.type === "BlockStatement" &&
                    (/Function/.test(grandparent.type))) &&
                    directives(parent).indexOf(node) >= 0;
        }
 
        /**
         * Determines whether or not a given node is a valid expression. Recurses on short circuit eval and ternary nodes if enabled by flags.
         * @param {ASTNode} node - any node
         * @returns {boolean} whether the given node is a valid expression
         */
        function isValidExpression(node) {
            if (allowTernary) {
 
                // Recursive check for ternary and logical expressions
                if (node.type === "ConditionalExpression") {
                    return isValidExpression(node.consequent) && isValidExpression(node.alternate);
                }
            }
 
            if (allowShortCircuit) {
                if (node.type === "LogicalExpression") {
                    return isValidExpression(node.right);
                }
            }
 
            if (allowTaggedTemplates && node.type === "TaggedTemplateExpression") {
                return true;
            }
 
            return /^(?:Assignment|Call|New|Update|Yield|Await)Expression$/.test(node.type) ||
                (node.type === "UnaryExpression" && ["delete", "void"].indexOf(node.operator) >= 0);
        }
 
        return {
            ExpressionStatement(node) {
                if (!isValidExpression(node.expression) && !isDirective(node, context.getAncestors())) {
                    context.report({ node, message: "Expected an assignment or function call and instead saw an expression." });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-unused-labels.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-unused-labels.js

Statements: 17.39% (4 / 23)      Branches: 0% (0 / 8)      Functions: 0% (0 / 5)      Lines: 17.39% (4 / 23)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107                      1                                             1                             1                                                             1                                                    
/**
 * @fileoverview Rule to disallow unused labels.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow unused labels",
            category: "Best Practices",
            recommended: true
        },
 
        schema: [],
 
        fixable: "code"
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
        let scopeInfo = null;
 
        /**
         * Adds a scope info to the stack.
         *
         * @param {ASTNode} node - A node to add. This is a LabeledStatement.
         * @returns {void}
         */
        function enterLabeledScope(node) {
            scopeInfo = {
                label: node.label.name,
                used: false,
                upper: scopeInfo
            };
        }
 
        /**
         * Removes the top of the stack.
         * At the same time, this reports the label if it's never used.
         *
         * @param {ASTNode} node - A node to report. This is a LabeledStatement.
         * @returns {void}
         */
        function exitLabeledScope(node) {
            if (!scopeInfo.used) {
                context.report({
                    node: node.label,
                    message: "'{{name}}:' is defined but never used.",
                    data: node.label,
                    fix(fixer) {
 
                        /*
                         * Only perform a fix if there are no comments between the label and the body. This will be the case
                         * when there is exactly one token/comment (the ":") between the label and the body.
                         */
                        if (sourceCode.getTokenAfter(node.label, { includeComments: true }) === sourceCode.getTokenBefore(node.body, { includeComments: true })) {
                            return fixer.removeRange([node.range[0], node.body.range[0]]);
                        }
 
                        return null;
                    }
                });
            }
 
            scopeInfo = scopeInfo.upper;
        }
 
        /**
         * Marks the label of a given node as used.
         *
         * @param {ASTNode} node - A node to mark. This is a BreakStatement or
         *      ContinueStatement.
         * @returns {void}
         */
        function markAsUsed(node) {
            if (!node.label) {
                return;
            }
 
            const label = node.label.name;
            let info = scopeInfo;
 
            while (info) {
                if (info.label === label) {
                    info.used = true;
                    break;
                }
                info = info.upper;
            }
        }
 
        return {
            LabeledStatement: enterLabeledScope,
            "LabeledStatement:exit": exitLabeledScope,
            BreakStatement: markAsUsed,
            ContinueStatement: markAsUsed
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-unused-vars.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-unused-vars.js

Statements: 10.34% (18 / 174)      Branches: 0% (0 / 155)      Functions: 0% (0 / 17)      Lines: 10.53% (18 / 171)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606                      1 1           1                                                                                                                                                                                               1                                                   1                                             1                     1                                           1                                             1                                                                           1                                                                                                           1                                   1                                                                   1                                                                       1                                                       1                                                       1                                                                                                                                                                                       1                                       1                                                                            
/**
 * @fileoverview Rule to flag declared but unused variables
 * @author Ilya Volodin
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const lodash = require("lodash");
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow unused variables",
            category: "Variables",
            recommended: true
        },
 
        schema: [
            {
                oneOf: [
                    {
                        enum: ["all", "local"]
                    },
                    {
                        type: "object",
                        properties: {
                            vars: {
                                enum: ["all", "local"]
                            },
                            varsIgnorePattern: {
                                type: "string"
                            },
                            args: {
                                enum: ["all", "after-used", "none"]
                            },
                            ignoreRestSiblings: {
                                type: "boolean"
                            },
                            argsIgnorePattern: {
                                type: "string"
                            },
                            caughtErrors: {
                                enum: ["all", "none"]
                            },
                            caughtErrorsIgnorePattern: {
                                type: "string"
                            }
                        }
                    }
                ]
            }
        ]
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        const DEFINED_MESSAGE = "'{{name}}' is defined but never used.";
        const ASSIGNED_MESSAGE = "'{{name}}' is assigned a value but never used.";
        const REST_PROPERTY_TYPE = /^(?:Experimental)?RestProperty$/;
 
        const config = {
            vars: "all",
            args: "after-used",
            ignoreRestSiblings: false,
            caughtErrors: "none"
        };
 
        const firstOption = context.options[0];
 
        if (firstOption) {
            if (typeof firstOption === "string") {
                config.vars = firstOption;
            } else {
                config.vars = firstOption.vars || config.vars;
                config.args = firstOption.args || config.args;
                config.ignoreRestSiblings = firstOption.ignoreRestSiblings || config.ignoreRestSiblings;
                config.caughtErrors = firstOption.caughtErrors || config.caughtErrors;
 
                if (firstOption.varsIgnorePattern) {
                    config.varsIgnorePattern = new RegExp(firstOption.varsIgnorePattern);
                }
 
                if (firstOption.argsIgnorePattern) {
                    config.argsIgnorePattern = new RegExp(firstOption.argsIgnorePattern);
                }
 
                if (firstOption.caughtErrorsIgnorePattern) {
                    config.caughtErrorsIgnorePattern = new RegExp(firstOption.caughtErrorsIgnorePattern);
                }
            }
        }
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        const STATEMENT_TYPE = /(?:Statement|Declaration)$/;
 
        /**
         * Determines if a given variable is being exported from a module.
         * @param {Variable} variable - EScope variable object.
         * @returns {boolean} True if the variable is exported, false if not.
         * @private
         */
        function isExported(variable) {
 
            const definition = variable.defs[0];
 
            if (definition) {
 
                let node = definition.node;
 
                if (node.type === "VariableDeclarator") {
                    node = node.parent;
                } else if (definition.type === "Parameter") {
                    return false;
                }
 
                return node.parent.type.indexOf("Export") === 0;
            }
            return false;
 
        }
 
        /**
         * Determines if a variable has a sibling rest property
         * @param {Variable} variable - EScope variable object.
         * @returns {boolean} True if the variable is exported, false if not.
         * @private
         */
        function hasRestSpreadSibling(variable) {
            if (config.ignoreRestSiblings) {
                return variable.defs.some(def => {
                    const propertyNode = def.name.parent;
                    const patternNode = propertyNode.parent;
 
                    return (
                        propertyNode.type === "Property" &&
                        patternNode.type === "ObjectPattern" &&
                        REST_PROPERTY_TYPE.test(patternNode.properties[patternNode.properties.length - 1].type)
                    );
                });
            }
 
            return false;
        }
 
        /**
         * Determines if a reference is a read operation.
         * @param {Reference} ref - An escope Reference
         * @returns {boolean} whether the given reference represents a read operation
         * @private
         */
        function isReadRef(ref) {
            return ref.isRead();
        }
 
        /**
         * Determine if an identifier is referencing an enclosing function name.
         * @param {Reference} ref - The reference to check.
         * @param {ASTNode[]} nodes - The candidate function nodes.
         * @returns {boolean} True if it's a self-reference, false if not.
         * @private
         */
        function isSelfReference(ref, nodes) {
            let scope = ref.from;
 
            while (scope) {
                if (nodes.indexOf(scope.block) >= 0) {
                    return true;
                }
 
                scope = scope.upper;
            }
 
            return false;
        }
 
        /**
         * Checks the position of given nodes.
         *
         * @param {ASTNode} inner - A node which is expected as inside.
         * @param {ASTNode} outer - A node which is expected as outside.
         * @returns {boolean} `true` if the `inner` node exists in the `outer` node.
         * @private
         */
        function isInside(inner, outer) {
            return (
                inner.range[0] >= outer.range[0] &&
                inner.range[1] <= outer.range[1]
            );
        }
 
        /**
         * If a given reference is left-hand side of an assignment, this gets
         * the right-hand side node of the assignment.
         *
         * In the following cases, this returns null.
         *
         * - The reference is not the LHS of an assignment expression.
         * - The reference is inside of a loop.
         * - The reference is inside of a function scope which is different from
         *   the declaration.
         *
         * @param {escope.Reference} ref - A reference to check.
         * @param {ASTNode} prevRhsNode - The previous RHS node.
         * @returns {ASTNode|null} The RHS node or null.
         * @private
         */
        function getRhsNode(ref, prevRhsNode) {
            const id = ref.identifier;
            const parent = id.parent;
            const granpa = parent.parent;
            const refScope = ref.from.variableScope;
            const varScope = ref.resolved.scope.variableScope;
            const canBeUsedLater = refScope !== varScope || astUtils.isInLoop(id);
 
            /*
             * Inherits the previous node if this reference is in the node.
             * This is for `a = a + a`-like code.
             */
            if (prevRhsNode && isInside(id, prevRhsNode)) {
                return prevRhsNode;
            }
 
            if (parent.type === "AssignmentExpression" &&
                granpa.type === "ExpressionStatement" &&
                id === parent.left &&
                !canBeUsedLater
            ) {
                return parent.right;
            }
            return null;
        }
 
        /**
         * Checks whether a given function node is stored to somewhere or not.
         * If the function node is stored, the function can be used later.
         *
         * @param {ASTNode} funcNode - A function node to check.
         * @param {ASTNode} rhsNode - The RHS node of the previous assignment.
         * @returns {boolean} `true` if under the following conditions:
         *      - the funcNode is assigned to a variable.
         *      - the funcNode is bound as an argument of a function call.
         *      - the function is bound to a property and the object satisfies above conditions.
         * @private
         */
        function isStorableFunction(funcNode, rhsNode) {
            let node = funcNode;
            let parent = funcNode.parent;
 
            while (parent && isInside(parent, rhsNode)) {
                switch (parent.type) {
                    case "SequenceExpression":
                        if (parent.expressions[parent.expressions.length - 1] !== node) {
                            return false;
                        }
                        break;
 
                    case "CallExpression":
                    case "NewExpression":
                        return parent.callee !== node;
 
                    case "AssignmentExpression":
                    case "TaggedTemplateExpression":
                    case "YieldExpression":
                        return true;
 
                    default:
                        if (STATEMENT_TYPE.test(parent.type)) {
 
                            /*
                             * If it encountered statements, this is a complex pattern.
                             * Since analyzeing complex patterns is hard, this returns `true` to avoid false positive.
                             */
                            return true;
                        }
                }
 
                node = parent;
                parent = parent.parent;
            }
 
            return false;
        }
 
        /**
         * Checks whether a given Identifier node exists inside of a function node which can be used later.
         *
         * "can be used later" means:
         * - the function is assigned to a variable.
         * - the function is bound to a property and the object can be used later.
         * - the function is bound as an argument of a function call.
         *
         * If a reference exists in a function which can be used later, the reference is read when the function is called.
         *
         * @param {ASTNode} id - An Identifier node to check.
         * @param {ASTNode} rhsNode - The RHS node of the previous assignment.
         * @returns {boolean} `true` if the `id` node exists inside of a function node which can be used later.
         * @private
         */
        function isInsideOfStorableFunction(id, rhsNode) {
            const funcNode = astUtils.getUpperFunction(id);
 
            return (
                funcNode &&
                isInside(funcNode, rhsNode) &&
                isStorableFunction(funcNode, rhsNode)
            );
        }
 
        /**
         * Checks whether a given reference is a read to update itself or not.
         *
         * @param {escope.Reference} ref - A reference to check.
         * @param {ASTNode} rhsNode - The RHS node of the previous assignment.
         * @returns {boolean} The reference is a read to update itself.
         * @private
         */
        function isReadForItself(ref, rhsNode) {
            const id = ref.identifier;
            const parent = id.parent;
            const granpa = parent.parent;
 
            return ref.isRead() && (
 
                // self update. e.g. `a += 1`, `a++`
                (
                    parent.type === "AssignmentExpression" &&
                    granpa.type === "ExpressionStatement" &&
                    parent.left === id
                ) ||
                (
                    parent.type === "UpdateExpression" &&
                    granpa.type === "ExpressionStatement"
                ) ||
 
                // in RHS of an assignment for itself. e.g. `a = a + 1`
                (
                    rhsNode &&
                    isInside(id, rhsNode) &&
                    !isInsideOfStorableFunction(id, rhsNode)
                )
            );
        }
 
        /**
         * Determine if an identifier is used either in for-in loops.
         *
         * @param {Reference} ref - The reference to check.
         * @returns {boolean} whether reference is used in the for-in loops
         * @private
         */
        function isForInRef(ref) {
            let target = ref.identifier.parent;
 
 
            // "for (var ...) { return; }"
            if (target.type === "VariableDeclarator") {
                target = target.parent.parent;
            }
 
            if (target.type !== "ForInStatement") {
                return false;
            }
 
            // "for (...) { return; }"
            if (target.body.type === "BlockStatement") {
                target = target.body.body[0];
 
            // "for (...) return;"
            } else {
                target = target.body;
            }
 
            // For empty loop body
            if (!target) {
                return false;
            }
 
            return target.type === "ReturnStatement";
        }
 
        /**
         * Determines if the variable is used.
         * @param {Variable} variable - The variable to check.
         * @returns {boolean} True if the variable is used
         * @private
         */
        function isUsedVariable(variable) {
            const functionNodes = variable.defs.filter(def => def.type === "FunctionName").map(def => def.node),
                isFunctionDefinition = functionNodes.length > 0;
            let rhsNode = null;
 
            return variable.references.some(ref => {
                if (isForInRef(ref)) {
                    return true;
                }
 
                const forItself = isReadForItself(ref, rhsNode);
 
                rhsNode = getRhsNode(ref, rhsNode);
 
                return (
                    isReadRef(ref) &&
                    !forItself &&
                    !(isFunctionDefinition && isSelfReference(ref, functionNodes))
                );
            });
        }
 
        /**
         * Checks whether the given variable is the last parameter in the non-ignored parameters.
         *
         * @param {escope.Variable} variable - The variable to check.
         * @returns {boolean} `true` if the variable is the last.
         */
        function isLastInNonIgnoredParameters(variable) {
            const def = variable.defs[0];
 
            // This is the last.
            if (def.index === def.node.params.length - 1) {
                return true;
            }
 
            // if all parameters preceded by this variable are ignored and unused, this is the last.
            if (config.argsIgnorePattern) {
                const params = context.getDeclaredVariables(def.node);
                const posteriorParams = params.slice(params.indexOf(variable) + 1);
 
                if (posteriorParams.every(v => v.references.length === 0 && config.argsIgnorePattern.test(v.name))) {
                    return true;
                }
            }
 
            return false;
        }
 
        /**
         * Gets an array of variables without read references.
         * @param {Scope} scope - an escope Scope object.
         * @param {Variable[]} unusedVars - an array that saving result.
         * @returns {Variable[]} unused variables of the scope and descendant scopes.
         * @private
         */
        function collectUnusedVariables(scope, unusedVars) {
            const variables = scope.variables;
            const childScopes = scope.childScopes;
            let i, l;
 
            if (scope.type !== "TDZ" && (scope.type !== "global" || config.vars === "all")) {
                for (i = 0, l = variables.length; i < l; ++i) {
                    const variable = variables[i];
 
                    // skip a variable of class itself name in the class scope
                    if (scope.type === "class" && scope.block.id === variable.identifiers[0]) {
                        continue;
                    }
 
                    // skip function expression names and variables marked with markVariableAsUsed()
                    if (scope.functionExpressionScope || variable.eslintUsed) {
                        continue;
                    }
 
                    // skip implicit "arguments" variable
                    if (scope.type === "function" && variable.name === "arguments" && variable.identifiers.length === 0) {
                        continue;
                    }
 
                    // explicit global variables don't have definitions.
                    const def = variable.defs[0];
 
                    if (def) {
                        const type = def.type;
 
                        // skip catch variables
                        if (type === "CatchClause") {
                            if (config.caughtErrors === "none") {
                                continue;
                            }
 
                            // skip ignored parameters
                            if (config.caughtErrorsIgnorePattern && config.caughtErrorsIgnorePattern.test(def.name.name)) {
                                continue;
                            }
                        }
 
                        if (type === "Parameter") {
 
                            // skip any setter argument
                            if ((def.node.parent.type === "Property" || def.node.parent.type === "MethodDefinition") && def.node.parent.kind === "set") {
                                continue;
                            }
 
                            // if "args" option is "none", skip any parameter
                            if (config.args === "none") {
                                continue;
                            }
 
                            // skip ignored parameters
                            if (config.argsIgnorePattern && config.argsIgnorePattern.test(def.name.name)) {
                                continue;
                            }
 
                            // if "args" option is "after-used", skip all but the last parameter
                            if (config.args === "after-used" && !isLastInNonIgnoredParameters(variable)) {
                                continue;
                            }
                        } else {
 
                            // skip ignored variables
                            if (config.varsIgnorePattern && config.varsIgnorePattern.test(def.name.name)) {
                                continue;
                            }
                        }
                    }
 
                    if (!isUsedVariable(variable) && !isExported(variable) && !hasRestSpreadSibling(variable)) {
                        unusedVars.push(variable);
                    }
                }
            }
 
            for (i = 0, l = childScopes.length; i < l; ++i) {
                collectUnusedVariables(childScopes[i], unusedVars);
            }
 
            return unusedVars;
        }
 
        /**
         * Gets the index of a given variable name in a given comment.
         * @param {escope.Variable} variable - A variable to get.
         * @param {ASTNode} comment - A comment node which includes the variable name.
         * @returns {number} The index of the variable name's location.
         * @private
         */
        function getColumnInComment(variable, comment) {
            const namePattern = new RegExp(`[\\s,]${lodash.escapeRegExp(variable.name)}(?:$|[\\s,:])`, "g");
 
            // To ignore the first text "global".
            namePattern.lastIndex = comment.value.indexOf("global") + 6;
 
            // Search a given variable name.
            const match = namePattern.exec(comment.value);
 
            return match ? match.index + 1 : 0;
        }
 
        /**
         * Creates the correct location of a given variables.
         * The location is at its name string in a `/*global` comment.
         *
         * @param {escope.Variable} variable - A variable to get its location.
         * @returns {{line: number, column: number}} The location object for the variable.
         * @private
         */
        function getLocation(variable) {
            const comment = variable.eslintExplicitGlobalComment;
 
            return sourceCode.getLocFromIndex(comment.range[0] + 2 + getColumnInComment(variable, comment));
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            "Program:exit"(programNode) {
                const unusedVars = collectUnusedVariables(context.getScope(), []);
 
                for (let i = 0, l = unusedVars.length; i < l; ++i) {
                    const unusedVar = unusedVars[i];
 
                    if (unusedVar.eslintExplicitGlobal) {
                        context.report({
                            node: programNode,
                            loc: getLocation(unusedVar),
                            message: DEFINED_MESSAGE,
                            data: unusedVar
                        });
                    } else if (unusedVar.defs.length > 0) {
                        context.report({
                            node: unusedVar.identifiers[0],
                            message: unusedVar.references.some(ref => ref.isWrite()) ? ASSIGNED_MESSAGE : DEFINED_MESSAGE,
                            data: unusedVar
                        });
                    }
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-use-before-define.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-use-before-define.js

Statements: 16.9% (12 / 71)      Branches: 0% (0 / 53)      Functions: 0% (0 / 12)      Lines: 16.9% (12 / 71)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266                      1 1               1                                           1                     1                         1                           1                                     1                                                                         1                                                                         1                                     1                                                                   1                                                                              
/**
 * @fileoverview Rule to flag use of variables before they are defined
 * @author Ilya Volodin
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const SENTINEL_TYPE = /^(?:(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|CatchClause|ImportDeclaration|ExportNamedDeclaration)$/;
const FOR_IN_OF_TYPE = /^For(?:In|Of)Statement$/;
 
/**
 * Parses a given value as options.
 *
 * @param {any} options - A value to parse.
 * @returns {Object} The parsed options.
 */
function parseOptions(options) {
    let functions = true;
    let classes = true;
    let variables = true;
 
    if (typeof options === "string") {
        functions = (options !== "nofunc");
    } else if (typeof options === "object" && options !== null) {
        functions = options.functions !== false;
        classes = options.classes !== false;
        variables = options.variables !== false;
    }
 
    return { functions, classes, variables };
}
 
/**
 * Checks whether or not a given variable is a function declaration.
 *
 * @param {escope.Variable} variable - A variable to check.
 * @returns {boolean} `true` if the variable is a function declaration.
 */
function isFunction(variable) {
    return variable.defs[0].type === "FunctionName";
}
 
/**
 * Checks whether or not a given variable is a class declaration in an upper function scope.
 *
 * @param {escope.Variable} variable - A variable to check.
 * @param {escope.Reference} reference - A reference to check.
 * @returns {boolean} `true` if the variable is a class declaration.
 */
function isOuterClass(variable, reference) {
    return (
        variable.defs[0].type === "ClassName" &&
        variable.scope.variableScope !== reference.from.variableScope
    );
}
 
/**
* Checks whether or not a given variable is a variable declaration in an upper function scope.
* @param {escope.Variable} variable - A variable to check.
* @param {escope.Reference} reference - A reference to check.
* @returns {boolean} `true` if the variable is a variable declaration.
*/
function isOuterVariable(variable, reference) {
    return (
        variable.defs[0].type === "Variable" &&
        variable.scope.variableScope !== reference.from.variableScope
    );
}
 
/**
 * Checks whether or not a given location is inside of the range of a given node.
 *
 * @param {ASTNode} node - An node to check.
 * @param {number} location - A location to check.
 * @returns {boolean} `true` if the location is inside of the range of the node.
 */
function isInRange(node, location) {
    return node && node.range[0] <= location && location <= node.range[1];
}
 
/**
 * Checks whether or not a given reference is inside of the initializers of a given variable.
 *
 * This returns `true` in the following cases:
 *
 *     var a = a
 *     var [a = a] = list
 *     var {a = a} = obj
 *     for (var a in a) {}
 *     for (var a of a) {}
 *
 * @param {Variable} variable - A variable to check.
 * @param {Reference} reference - A reference to check.
 * @returns {boolean} `true` if the reference is inside of the initializers.
 */
function isInInitializer(variable, reference) {
    if (variable.scope !== reference.from) {
        return false;
    }
 
    let node = variable.identifiers[0].parent;
    const location = reference.identifier.range[1];
 
    while (node) {
        if (node.type === "VariableDeclarator") {
            if (isInRange(node.init, location)) {
                return true;
            }
            if (FOR_IN_OF_TYPE.test(node.parent.parent.type) &&
                isInRange(node.parent.parent.right, location)
            ) {
                return true;
            }
            break;
        } else if (node.type === "AssignmentPattern") {
            if (isInRange(node.right, location)) {
                return true;
            }
        } else if (SENTINEL_TYPE.test(node.type)) {
            break;
        }
 
        node = node.parent;
    }
 
    return false;
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow the use of variables before they are defined",
            category: "Variables",
            recommended: false
        },
 
        schema: [
            {
                oneOf: [
                    {
                        enum: ["nofunc"]
                    },
                    {
                        type: "object",
                        properties: {
                            functions: { type: "boolean" },
                            classes: { type: "boolean" },
                            variables: { type: "boolean" }
                        },
                        additionalProperties: false
                    }
                ]
            }
        ]
    },
 
    create(context) {
        const options = parseOptions(context.options[0]);
 
        /**
         * Determines whether a given use-before-define case should be reported according to the options.
         * @param {escope.Variable} variable The variable that gets used before being defined
         * @param {escope.Reference} reference The reference to the variable
         * @returns {boolean} `true` if the usage should be reported
         */
        function isForbidden(variable, reference) {
            if (isFunction(variable)) {
                return options.functions;
            }
            if (isOuterClass(variable, reference)) {
                return options.classes;
            }
            if (isOuterVariable(variable, reference)) {
                return options.variables;
            }
            return true;
        }
 
        /**
         * Finds and validates all variables in a given scope.
         * @param {Scope} scope The scope object.
         * @returns {void}
         * @private
         */
        function findVariablesInScope(scope) {
            scope.references.forEach(reference => {
                const variable = reference.resolved;
 
                // Skips when the reference is:
                // - initialization's.
                // - referring to an undefined variable.
                // - referring to a global environment variable (there're no identifiers).
                // - located preceded by the variable (except in initializers).
                // - allowed by options.
                if (reference.init ||
                    !variable ||
                    variable.identifiers.length === 0 ||
                    (variable.identifiers[0].range[1] < reference.identifier.range[1] && !isInInitializer(variable, reference)) ||
                    !isForbidden(variable, reference)
                ) {
                    return;
                }
 
                // Reports.
                context.report({
                    node: reference.identifier,
                    message: "'{{name}}' was used before it was defined.",
                    data: reference.identifier
                });
            });
        }
 
        /**
         * Validates variables inside of a node's scope.
         * @param {ASTNode} node The node to check.
         * @returns {void}
         * @private
         */
        function findVariables() {
            const scope = context.getScope();
 
            findVariablesInScope(scope);
        }
 
        const ruleDefinition = {
            "Program:exit"(node) {
                const scope = context.getScope(),
                    ecmaFeatures = context.parserOptions.ecmaFeatures || {};
 
                findVariablesInScope(scope);
 
                // both Node.js and Modules have an extra scope
                if (ecmaFeatures.globalReturn || node.sourceType === "module") {
                    findVariablesInScope(scope.childScopes[0]);
                }
            }
        };
 
        if (context.parserOptions.ecmaVersion >= 6) {
            ruleDefinition["BlockStatement:exit"] =
                ruleDefinition["SwitchStatement:exit"] = findVariables;
 
            ruleDefinition["ArrowFunctionExpression:exit"] = function(node) {
                if (node.body.type !== "BlockStatement") {
                    findVariables(node);
                }
            };
        } else {
            ruleDefinition["FunctionExpression:exit"] =
                ruleDefinition["FunctionDeclaration:exit"] =
                ruleDefinition["ArrowFunctionExpression:exit"] = findVariables;
        }
 
        return ruleDefinition;
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-useless-call.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-useless-call.js

Statements: 19.23% (5 / 26)      Branches: 0% (0 / 22)      Functions: 0% (0 / 5)      Lines: 19.23% (5 / 26)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106              1                     1                                     1                                                 1                     1                                                                
/**
 * @fileoverview A rule to disallow unnecessary `.call()` and `.apply()`.
 * @author Toru Nagashima
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks whether or not a node is a `.call()`/`.apply()`.
 * @param {ASTNode} node - A CallExpression node to check.
 * @returns {boolean} Whether or not the node is a `.call()`/`.apply()`.
 */
function isCallOrNonVariadicApply(node) {
    return (
        node.callee.type === "MemberExpression" &&
        node.callee.property.type === "Identifier" &&
        node.callee.computed === false &&
        (
            (node.callee.property.name === "call" && node.arguments.length >= 1) ||
            (node.callee.property.name === "apply" && node.arguments.length === 2 && node.arguments[1].type === "ArrayExpression")
        )
    );
}
 
/**
 * Checks whether or not the tokens of two given nodes are same.
 * @param {ASTNode} left - A node 1 to compare.
 * @param {ASTNode} right - A node 2 to compare.
 * @param {SourceCode} sourceCode - The ESLint source code object.
 * @returns {boolean} the source code for the given node.
 */
function equalTokens(left, right, sourceCode) {
    const tokensL = sourceCode.getTokens(left);
    const tokensR = sourceCode.getTokens(right);
 
    if (tokensL.length !== tokensR.length) {
        return false;
    }
    for (let i = 0; i < tokensL.length; ++i) {
        if (tokensL[i].type !== tokensR[i].type ||
            tokensL[i].value !== tokensR[i].value
        ) {
            return false;
        }
    }
 
    return true;
}
 
/**
 * Checks whether or not `thisArg` is not changed by `.call()`/`.apply()`.
 * @param {ASTNode|null} expectedThis - The node that is the owner of the applied function.
 * @param {ASTNode} thisArg - The node that is given to the first argument of the `.call()`/`.apply()`.
 * @param {SourceCode} sourceCode - The ESLint source code object.
 * @returns {boolean} Whether or not `thisArg` is not changed by `.call()`/`.apply()`.
 */
function isValidThisArg(expectedThis, thisArg, sourceCode) {
    if (!expectedThis) {
        return astUtils.isNullOrUndefined(thisArg);
    }
    return equalTokens(expectedThis, thisArg, sourceCode);
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow unnecessary calls to `.call()` and `.apply()`",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        return {
            CallExpression(node) {
                if (!isCallOrNonVariadicApply(node)) {
                    return;
                }
 
                const applied = node.callee.object;
                const expectedThis = (applied.type === "MemberExpression") ? applied.object : null;
                const thisArg = node.arguments[0];
 
                if (isValidThisArg(expectedThis, thisArg, sourceCode)) {
                    context.report({ node, message: "unnecessary '.{{name}}()'.", data: { name: node.callee.property.name } });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-useless-computed-key.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-useless-computed-key.js

Statements: 19.05% (4 / 21)      Branches: 0% (0 / 15)      Functions: 0% (0 / 3)      Lines: 20% (4 / 20)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78                    1 1           1   1                                                                                                                    
/**
 * @fileoverview Rule to disallow unnecessary computed property keys in object literals
 * @author Burak Yigit Kaya
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
const esUtils = require("esutils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
const MESSAGE_UNNECESSARY_COMPUTED = "Unnecessarily computed property [{{property}}] found.";
 
module.exports = {
    meta: {
        docs: {
            description: "disallow unnecessary computed property keys in object literals",
            category: "ECMAScript 6",
            recommended: false
        },
 
        schema: [],
 
        fixable: "code"
    },
    create(context) {
        const sourceCode = context.getSourceCode();
 
        return {
            Property(node) {
                if (!node.computed) {
                    return;
                }
 
                const key = node.key,
                    nodeType = typeof key.value;
 
                if (key.type === "Literal" && (nodeType === "string" || nodeType === "number") && key.value !== "__proto__") {
                    context.report({
                        node,
                        message: MESSAGE_UNNECESSARY_COMPUTED,
                        data: { property: sourceCode.getText(key) },
                        fix(fixer) {
                            const leftSquareBracket = sourceCode.getFirstToken(node, astUtils.isOpeningBracketToken);
                            const rightSquareBracket = sourceCode.getFirstTokenBetween(node.key, node.value, astUtils.isClosingBracketToken);
                            const tokensBetween = sourceCode.getTokensBetween(leftSquareBracket, rightSquareBracket, 1);
 
                            if (tokensBetween.slice(0, -1).some((token, index) => sourceCode.getText().slice(token.range[1], tokensBetween[index + 1].range[0]).trim())) {
 
                                // If there are comments between the brackets and the property name, don't do a fix.
                                return null;
                            }
 
                            const tokenBeforeLeftBracket = sourceCode.getTokenBefore(leftSquareBracket);
 
                            // Insert a space before the key to avoid changing identifiers, e.g. ({ get[2]() {} }) to ({ get2() {} })
                            const needsSpaceBeforeKey = tokenBeforeLeftBracket.range[1] === leftSquareBracket.range[0] &&
                                esUtils.code.isIdentifierPartES6(tokenBeforeLeftBracket.value.slice(-1).charCodeAt(0)) &&
                                esUtils.code.isIdentifierPartES6(key.raw.charCodeAt(0));
 
                            const replacementKey = (needsSpaceBeforeKey ? " " : "") + key.raw;
 
                            return fixer.replaceTextRange([leftSquareBracket.range[0], rightSquareBracket.range[1]], replacementKey);
                        }
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-useless-concat.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-useless-concat.js

Statements: 24% (6 / 25)      Branches: 0% (0 / 11)      Functions: 0% (0 / 6)      Lines: 24% (6 / 25)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110                    1                     1                 1                 1                           1                         1                                                                                      
/**
 * @fileoverview disallow unncessary concatenation of template strings
 * @author Henry Zhu
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks whether or not a given node is a concatenation.
 * @param {ASTNode} node - A node to check.
 * @returns {boolean} `true` if the node is a concatenation.
 */
function isConcatenation(node) {
    return node.type === "BinaryExpression" && node.operator === "+";
}
 
/**
 * Checks if the given token is a `+` token or not.
 * @param {Token} token - The token to check.
 * @returns {boolean} `true` if the token is a `+` token.
 */
function isConcatOperatorToken(token) {
    return token.value === "+" && token.type === "Punctuator";
}
 
/**
 * Get's the right most node on the left side of a BinaryExpression with + operator.
 * @param {ASTNode} node - A BinaryExpression node to check.
 * @returns {ASTNode} node
 */
function getLeft(node) {
    let left = node.left;
 
    while (isConcatenation(left)) {
        left = left.right;
    }
    return left;
}
 
/**
 * Get's the left most node on the right side of a BinaryExpression with + operator.
 * @param {ASTNode} node - A BinaryExpression node to check.
 * @returns {ASTNode} node
 */
function getRight(node) {
    let right = node.right;
 
    while (isConcatenation(right)) {
        right = right.left;
    }
    return right;
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow unnecessary concatenation of literals or template literals",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        return {
            BinaryExpression(node) {
 
                // check if not concatenation
                if (node.operator !== "+") {
                    return;
                }
 
                // account for the `foo + "a" + "b"` case
                const left = getLeft(node);
                const right = getRight(node);
 
                if (astUtils.isStringLiteral(left) &&
                    astUtils.isStringLiteral(right) &&
                    astUtils.isTokenOnSameLine(left, right)
                ) {
                    const operatorToken = sourceCode.getFirstTokenBetween(left, right, isConcatOperatorToken);
 
                    context.report({
                        node,
                        loc: operatorToken.loc.start,
                        message: "Unexpected string concatenation of literals."
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-useless-constructor.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-useless-constructor.js

Statements: 32.26% (10 / 31)      Branches: 0% (0 / 32)      Functions: 0% (0 / 10)      Lines: 32.26% (10 / 31)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184                                1                               1                     1                                 1                               1                             1                             1                                         1                             1                                   1                                              
/**
 * @fileoverview Rule to flag the use of redundant constructors in classes.
 * @author Alberto Rodríguez
 */
"use strict";
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks whether a given array of statements is a single call of `super`.
 *
 * @param {ASTNode[]} body - An array of statements to check.
 * @returns {boolean} `true` if the body is a single call of `super`.
 */
function isSingleSuperCall(body) {
    return (
        body.length === 1 &&
        body[0].type === "ExpressionStatement" &&
        body[0].expression.type === "CallExpression" &&
        body[0].expression.callee.type === "Super"
    );
}
 
/**
 * Checks whether a given node is a pattern which doesn't have any side effects.
 * Default parameters and Destructuring parameters can have side effects.
 *
 * @param {ASTNode} node - A pattern node.
 * @returns {boolean} `true` if the node doesn't have any side effects.
 */
function isSimple(node) {
    return node.type === "Identifier" || node.type === "RestElement";
}
 
/**
 * Checks whether a given array of expressions is `...arguments` or not.
 * `super(...arguments)` passes all arguments through.
 *
 * @param {ASTNode[]} superArgs - An array of expressions to check.
 * @returns {boolean} `true` if the superArgs is `...arguments`.
 */
function isSpreadArguments(superArgs) {
    return (
        superArgs.length === 1 &&
        superArgs[0].type === "SpreadElement" &&
        superArgs[0].argument.type === "Identifier" &&
        superArgs[0].argument.name === "arguments"
    );
}
 
/**
 * Checks whether given 2 nodes are identifiers which have the same name or not.
 *
 * @param {ASTNode} ctorParam - A node to check.
 * @param {ASTNode} superArg - A node to check.
 * @returns {boolean} `true` if the nodes are identifiers which have the same
 *      name.
 */
function isValidIdentifierPair(ctorParam, superArg) {
    return (
        ctorParam.type === "Identifier" &&
        superArg.type === "Identifier" &&
        ctorParam.name === superArg.name
    );
}
 
/**
 * Checks whether given 2 nodes are a rest/spread pair which has the same values.
 *
 * @param {ASTNode} ctorParam - A node to check.
 * @param {ASTNode} superArg - A node to check.
 * @returns {boolean} `true` if the nodes are a rest/spread pair which has the
 *      same values.
 */
function isValidRestSpreadPair(ctorParam, superArg) {
    return (
        ctorParam.type === "RestElement" &&
        superArg.type === "SpreadElement" &&
        isValidIdentifierPair(ctorParam.argument, superArg.argument)
    );
}
 
/**
 * Checks whether given 2 nodes have the same value or not.
 *
 * @param {ASTNode} ctorParam - A node to check.
 * @param {ASTNode} superArg - A node to check.
 * @returns {boolean} `true` if the nodes have the same value or not.
 */
function isValidPair(ctorParam, superArg) {
    return (
        isValidIdentifierPair(ctorParam, superArg) ||
        isValidRestSpreadPair(ctorParam, superArg)
    );
}
 
/**
 * Checks whether the parameters of a constructor and the arguments of `super()`
 * have the same values or not.
 *
 * @param {ASTNode} ctorParams - The parameters of a constructor to check.
 * @param {ASTNode} superArgs - The arguments of `super()` to check.
 * @returns {boolean} `true` if those have the same values.
 */
function isPassingThrough(ctorParams, superArgs) {
    if (ctorParams.length !== superArgs.length) {
        return false;
    }
 
    for (let i = 0; i < ctorParams.length; ++i) {
        if (!isValidPair(ctorParams[i], superArgs[i])) {
            return false;
        }
    }
 
    return true;
}
 
/**
 * Checks whether the constructor body is a redundant super call.
 *
 * @param {Array} body - constructor body content.
 * @param {Array} ctorParams - The params to check against super call.
 * @returns {boolean} true if the construtor body is redundant
 */
function isRedundantSuperCall(body, ctorParams) {
    return (
        isSingleSuperCall(body) &&
        ctorParams.every(isSimple) &&
        (
            isSpreadArguments(body[0].expression.arguments) ||
            isPassingThrough(ctorParams, body[0].expression.arguments)
        )
    );
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow unnecessary constructors",
            category: "ECMAScript 6",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        /**
         * Checks whether a node is a redundant constructor
         * @param {ASTNode} node - node to check
         * @returns {void}
         */
        function checkForConstructor(node) {
            if (node.kind !== "constructor") {
                return;
            }
 
            const body = node.value.body.body;
            const ctorParams = node.value.params;
            const superClass = node.parent.parent.superClass;
 
            if (superClass ? isRedundantSuperCall(body, ctorParams) : (body.length === 0)) {
                context.report({
                    node,
                    message: "Useless constructor."
                });
            }
        }
 
        return {
            MethodDefinition: checkForConstructor
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-useless-escape.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-useless-escape.js

Statements: 21.31% (13 / 61)      Branches: 0% (0 / 53)      Functions: 28.57% (2 / 7)      Lines: 21.31% (13 / 61)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217              1                       1 2 2 2       1 1 1                                     1                                                 1                                         1                                 1                                                                       1                                                                                                                                            
/**
 * @fileoverview Look for useless escapes in strings and regexes
 * @author Onur Temizkan
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
/**
* Returns the union of two sets.
* @param {Set} setA The first set
* @param {Set} setB The second set
* @returns {Set} The union of the two sets
*/
function union(setA, setB) {
    return new Set(function *() {
        yield* setA;
        yield* setB;
    }());
}
 
const VALID_STRING_ESCAPES = union(new Set("\\nrvtbfux"), astUtils.LINEBREAKS);
const REGEX_GENERAL_ESCAPES = new Set("\\bcdDfnrsStvwWxu0123456789]");
const REGEX_NON_CHARCLASS_ESCAPES = union(REGEX_GENERAL_ESCAPES, new Set("^/.$*+?[{}|()B"));
 
/**
* Parses a regular expression into a list of characters with character class info.
* @param {string} regExpText The raw text used to create the regular expression
* @returns {Object[]} A list of characters, each with info on escaping and whether they're in a character class.
* @example
*
* parseRegExp('a\\b[cd-]')
*
* returns:
* [
*   {text: 'a', index: 0, escaped: false, inCharClass: false, startsCharClass: false, endsCharClass: false},
*   {text: 'b', index: 2, escaped: true, inCharClass: false, startsCharClass: false, endsCharClass: false},
*   {text: 'c', index: 4, escaped: false, inCharClass: true, startsCharClass: true, endsCharClass: false},
*   {text: 'd', index: 5, escaped: false, inCharClass: true, startsCharClass: false, endsCharClass: false},
*   {text: '-', index: 6, escaped: false, inCharClass: true, startsCharClass: false, endsCharClass: false}
* ]
*/
function parseRegExp(regExpText) {
    const charList = [];
 
    regExpText.split("").reduce((state, char, index) => {
        if (!state.escapeNextChar) {
            if (char === "\\") {
                return Object.assign(state, { escapeNextChar: true });
            }
            if (char === "[" && !state.inCharClass) {
                return Object.assign(state, { inCharClass: true, startingCharClass: true });
            }
            if (char === "]" && state.inCharClass) {
                if (charList.length && charList[charList.length - 1].inCharClass) {
                    charList[charList.length - 1].endsCharClass = true;
                }
                return Object.assign(state, { inCharClass: false, startingCharClass: false });
            }
        }
        charList.push({ text: char, index, escaped: state.escapeNextChar, inCharClass: state.inCharClass, startsCharClass: state.startingCharClass, endsCharClass: false });
        return Object.assign(state, { escapeNextChar: false, startingCharClass: false });
    }, { escapeNextChar: false, inCharClass: false, startingCharClass: false });
 
    return charList;
}
 
module.exports = {
    meta: {
        docs: {
            description: "disallow unnecessary escape characters",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        /**
         * Reports a node
         * @param {ASTNode} node The node to report
         * @param {number} startOffset The backslash's offset from the start of the node
         * @param {string} character The uselessly escaped character (not including the backslash)
         * @returns {void}
         */
        function report(node, startOffset, character) {
            context.report({
                node,
                loc: sourceCode.getLocFromIndex(sourceCode.getIndexFromLoc(node.loc.start) + startOffset),
                message: "Unnecessary escape character: \\{{character}}.",
                data: { character }
            });
        }
 
        /**
         * Checks if the escape character in given string slice is unnecessary.
         *
         * @private
         * @param {ASTNode} node - node to validate.
         * @param {string} match - string slice to validate.
         * @returns {void}
         */
        function validateString(node, match) {
            const isTemplateElement = node.type === "TemplateElement";
            const escapedChar = match[0][1];
            let isUnnecessaryEscape = !VALID_STRING_ESCAPES.has(escapedChar);
            let isQuoteEscape;
 
            if (isTemplateElement) {
                isQuoteEscape = escapedChar === "`";
 
                if (escapedChar === "$") {
 
                    // Warn if `\$` is not followed by `{`
                    isUnnecessaryEscape = match.input[match.index + 2] !== "{";
                } else if (escapedChar === "{") {
 
                    /* Warn if `\{` is not preceded by `$`. If preceded by `$`, escaping
                     * is necessary and the rule should not warn. If preceded by `/$`, the rule
                     * will warn for the `/$` instead, as it is the first unnecessarily escaped character.
                     */
                    isUnnecessaryEscape = match.input[match.index - 1] !== "$";
                }
            } else {
                isQuoteEscape = escapedChar === node.raw[0];
            }
 
            if (isUnnecessaryEscape && !isQuoteEscape) {
                report(node, match.index + 1, match[0].slice(1));
            }
        }
 
        /**
         * Checks if a node has an escape.
         *
         * @param {ASTNode} node - node to check.
         * @returns {void}
         */
        function check(node) {
            const isTemplateElement = node.type === "TemplateElement";
 
            if (
                isTemplateElement &&
                node.parent &&
                node.parent.parent &&
                node.parent.parent.type === "TaggedTemplateExpression" &&
                node.parent === node.parent.parent.quasi
            ) {
 
                // Don't report tagged template literals, because the backslash character is accessible to the tag function.
                return;
            }
 
            if (typeof node.value === "string" || isTemplateElement) {
 
                /*
                 * JSXAttribute doesn't have any escape sequence: https://facebook.github.io/jsx/.
                 * In addition, backticks are not supported by JSX yet: https://github.com/facebook/jsx/issues/25.
                 */
                if (node.parent.type === "JSXAttribute" || node.parent.type === "JSXElement") {
                    return;
                }
 
                const value = isTemplateElement ? node.value.raw : node.raw.slice(1, -1);
                const pattern = /\\[^\d]/g;
                let match;
 
                while ((match = pattern.exec(value))) {
                    validateString(node, match);
                }
            } else if (node.regex) {
                parseRegExp(node.regex.pattern)
 
                    /*
                     * The '-' character is a special case, because it's only valid to escape it if it's in a character
                     * class, and is not at either edge of the character class. To account for this, don't consider '-'
                     * characters to be valid in general, and filter out '-' characters that appear in the middle of a
                     * character class.
                     */
                    .filter(charInfo => !(charInfo.text === "-" && charInfo.inCharClass && !charInfo.startsCharClass && !charInfo.endsCharClass))
 
                    /*
                     * The '^' character is also a special case; it must always be escaped outside of character classes, but
                     * it only needs to be escaped in character classes if it's at the beginning of the character class. To
                     * account for this, consider it to be a valid escape character outside of character classes, and filter
                     * out '^' characters that appear at the start of a character class.
                     */
                    .filter(charInfo => !(charInfo.text === "^" && charInfo.startsCharClass))
 
                    // Filter out characters that aren't escaped.
                    .filter(charInfo => charInfo.escaped)
 
                    // Filter out characters that are valid to escape, based on their position in the regular expression.
                    .filter(charInfo => !(charInfo.inCharClass ? REGEX_GENERAL_ESCAPES : REGEX_NON_CHARCLASS_ESCAPES).has(charInfo.text))
 
                    // Report all the remaining characters.
                    .forEach(charInfo => report(node, charInfo.index, charInfo.text));
            }
 
        }
 
        return {
            Literal: check,
            TemplateElement: check
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-useless-rename.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-useless-rename.js

Statements: 17.86% (5 / 28)      Branches: 0% (0 / 30)      Functions: 0% (0 / 6)      Lines: 17.86% (5 / 28)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149                      1                                                                             1                                               1                                                                   1                               1                                                
/**
 * @fileoverview Disallow renaming import, export, and destructured assignments to the same name.
 * @author Kai Cataldo
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow renaming import, export, and destructured assignments to the same name",
            category: "ECMAScript 6",
            recommended: false
        },
        fixable: "code",
        schema: [
            {
                type: "object",
                properties: {
                    ignoreDestructuring: { type: "boolean" },
                    ignoreImport: { type: "boolean" },
                    ignoreExport: { type: "boolean" }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const options = context.options[0] || {},
            ignoreDestructuring = options.ignoreDestructuring === true,
            ignoreImport = options.ignoreImport === true,
            ignoreExport = options.ignoreExport === true;
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Reports error for unnecessarily renamed assignments
         * @param {ASTNode} node - node to report
         * @param {ASTNode} initial - node with initial name value
         * @param {ASTNode} result - node with new name value
         * @param {string} type - the type of the offending node
         * @returns {void}
         */
        function reportError(node, initial, result, type) {
            const name = initial.type === "Identifier" ? initial.name : initial.value;
 
            return context.report({
                node,
                message: "{{type}} {{name}} unnecessarily renamed.",
                data: {
                    name,
                    type
                },
                fix(fixer) {
                    return fixer.replaceTextRange([
                        initial.range[0],
                        result.range[1]
                    ], name);
                }
            });
        }
 
        /**
         * Checks whether a destructured assignment is unnecessarily renamed
         * @param {ASTNode} node - node to check
         * @returns {void}
         */
        function checkDestructured(node) {
            if (ignoreDestructuring) {
                return;
            }
 
            const properties = node.properties;
 
            for (let i = 0; i < properties.length; i++) {
                if (properties[i].shorthand) {
                    continue;
                }
 
                /**
                 * If an ObjectPattern property is computed, we have no idea
                 * if a rename is useless or not. If an ObjectPattern property
                 * lacks a key, it is likely an ExperimentalRestProperty and
                 * so there is no "renaming" occurring here.
                 */
                if (properties[i].computed || !properties[i].key) {
                    continue;
                }
 
                if (properties[i].key.type === "Identifier" && properties[i].key.name === properties[i].value.name ||
                        properties[i].key.type === "Literal" && properties[i].key.value === properties[i].value.name) {
                    reportError(properties[i], properties[i].key, properties[i].value, "Destructuring assignment");
                }
            }
        }
 
        /**
         * Checks whether an import is unnecessarily renamed
         * @param {ASTNode} node - node to check
         * @returns {void}
         */
        function checkImport(node) {
            if (ignoreImport) {
                return;
            }
 
            if (node.imported.name === node.local.name &&
                    node.imported.range[0] !== node.local.range[0]) {
                reportError(node, node.imported, node.local, "Import");
            }
        }
 
        /**
         * Checks whether an export is unnecessarily renamed
         * @param {ASTNode} node - node to check
         * @returns {void}
         */
        function checkExport(node) {
            if (ignoreExport) {
                return;
            }
 
            if (node.local.name === node.exported.name &&
                    node.local.range[0] !== node.exported.range[0]) {
                reportError(node, node.local, node.exported, "Export");
            }
 
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            ObjectPattern: checkDestructured,
            ImportSpecifier: checkImport,
            ExportSpecifier: checkExport
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-useless-return.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-useless-return.js

Statements: 15.63% (10 / 64)      Branches: 0% (0 / 30)      Functions: 0% (0 / 13)      Lines: 15.63% (10 / 64)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300                    1                           1                 1                           1                   1                               1                                           1                                                 1                                                                                 1                                                             1                                                                                                                                                                                                                      
/**
 * @fileoverview Disallow redundant return statements
 * @author Teddy Katz
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils"),
    FixTracker = require("../util/fix-tracker");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Adds all elements of 2nd argument into 1st argument.
 *
 * @param {Array} array - The destination array to add.
 * @param {Array} elements - The source array to add.
 * @returns {void}
 */
const pushAll = Function.apply.bind(Array.prototype.push);
 
/**
 * Removes the given element from the array.
 *
 * @param {Array} array - The source array to remove.
 * @param {any} element - The target item to remove.
 * @returns {void}
 */
function remove(array, element) {
    const index = array.indexOf(element);
 
    if (index !== -1) {
        array.splice(index, 1);
    }
}
 
/**
 * Checks whether it can remove the given return statement or not.
 *
 * @param {ASTNode} node - The return statement node to check.
 * @returns {boolean} `true` if the node is removeable.
 */
function isRemovable(node) {
    return astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type);
}
 
/**
 * Checks whether the given return statement is in a `finally` block or not.
 *
 * @param {ASTNode} node - The return statement node to check.
 * @returns {boolean} `true` if the node is in a `finally` block.
 */
function isInFinally(node) {
    while (node && node.parent && !astUtils.isFunction(node)) {
        if (node.parent.type === "TryStatement" && node.parent.finalizer === node) {
            return true;
        }
 
        node = node.parent;
    }
 
    return false;
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow redundant return statements",
            category: "Best Practices",
            recommended: false
        },
        fixable: "code",
        schema: []
    },
 
    create(context) {
        const segmentInfoMap = new WeakMap();
        const usedUnreachableSegments = new WeakSet();
        let scopeInfo = null;
 
        /**
         * Checks whether the given segment is terminated by a return statement or not.
         *
         * @param {CodePathSegment} segment - The segment to check.
         * @returns {boolean} `true` if the segment is terminated by a return statement, or if it's still a part of unreachable.
         */
        function isReturned(segment) {
            const info = segmentInfoMap.get(segment);
 
            return !info || info.returned;
        }
 
        /**
         * Collects useless return statements from the given previous segments.
         *
         * A previous segment may be an unreachable segment.
         * In that case, the information object of the unreachable segment is not
         * initialized because `onCodePathSegmentStart` event is not notified for
         * unreachable segments.
         * This goes to the previous segments of the unreachable segment recursively
         * if the unreachable segment was generated by a return statement. Otherwise,
         * this ignores the unreachable segment.
         *
         * This behavior would simulate code paths for the case that the return
         * statement does not exist.
         *
         * @param {ASTNode[]} uselessReturns - The collected return statements.
         * @param {CodePathSegment[]} prevSegments - The previous segments to traverse.
         * @param {WeakSet<CodePathSegment>} [traversedSegments] A set of segments that have already been traversed in this call
         * @returns {ASTNode[]} `uselessReturns`.
         */
        function getUselessReturns(uselessReturns, prevSegments, traversedSegments) {
            if (!traversedSegments) {
                traversedSegments = new WeakSet();
            }
            for (const segment of prevSegments) {
                if (!segment.reachable) {
                    if (!traversedSegments.has(segment)) {
                        traversedSegments.add(segment);
                        getUselessReturns(
                            uselessReturns,
                            segment.allPrevSegments.filter(isReturned),
                            traversedSegments
                        );
                    }
                    continue;
                }
 
                pushAll(uselessReturns, segmentInfoMap.get(segment).uselessReturns);
            }
 
            return uselessReturns;
        }
 
        /**
         * Removes the return statements on the given segment from the useless return
         * statement list.
         *
         * This segment may be an unreachable segment.
         * In that case, the information object of the unreachable segment is not
         * initialized because `onCodePathSegmentStart` event is not notified for
         * unreachable segments.
         * This goes to the previous segments of the unreachable segment recursively
         * if the unreachable segment was generated by a return statement. Otherwise,
         * this ignores the unreachable segment.
         *
         * This behavior would simulate code paths for the case that the return
         * statement does not exist.
         *
         * @param {CodePathSegment} segment - The segment to get return statements.
         * @returns {void}
         */
        function markReturnStatementsOnSegmentAsUsed(segment) {
            if (!segment.reachable) {
                usedUnreachableSegments.add(segment);
                segment.allPrevSegments
                    .filter(isReturned)
                    .filter(prevSegment => !usedUnreachableSegments.has(prevSegment))
                    .forEach(markReturnStatementsOnSegmentAsUsed);
                return;
            }
 
            const info = segmentInfoMap.get(segment);
 
            for (const node of info.uselessReturns) {
                remove(scopeInfo.uselessReturns, node);
            }
            info.uselessReturns = [];
        }
 
        /**
         * Removes the return statements on the current segments from the useless
         * return statement list.
         *
         * This function will be called at every statement except FunctionDeclaration,
         * BlockStatement, and BreakStatement.
         *
         * - FunctionDeclarations are always executed whether it's returned or not.
         * - BlockStatements do nothing.
         * - BreakStatements go the next merely.
         *
         * @returns {void}
         */
        function markReturnStatementsOnCurrentSegmentsAsUsed() {
            scopeInfo
                .codePath
                .currentSegments
                .forEach(markReturnStatementsOnSegmentAsUsed);
        }
 
        //----------------------------------------------------------------------
        // Public
        //----------------------------------------------------------------------
 
        return {
 
            // Makes and pushs a new scope information.
            onCodePathStart(codePath) {
                scopeInfo = {
                    upper: scopeInfo,
                    uselessReturns: [],
                    codePath
                };
            },
 
            // Reports useless return statements if exist.
            onCodePathEnd() {
                for (const node of scopeInfo.uselessReturns) {
                    context.report({
                        node,
                        loc: node.loc,
                        message: "Unnecessary return statement.",
                        fix(fixer) {
                            if (isRemovable(node)) {
 
                                // Extend the replacement range to include the
                                // entire function to avoid conflicting with
                                // no-else-return.
                                // https://github.com/eslint/eslint/issues/8026
                                return new FixTracker(fixer, context.getSourceCode())
                                    .retainEnclosingFunction(node)
                                    .remove(node);
                            }
                            return null;
                        }
                    });
                }
 
                scopeInfo = scopeInfo.upper;
            },
 
            // Initializes segments.
            // NOTE: This event is notified for only reachable segments.
            onCodePathSegmentStart(segment) {
                const info = {
                    uselessReturns: getUselessReturns([], segment.allPrevSegments),
                    returned: false
                };
 
                // Stores the info.
                segmentInfoMap.set(segment, info);
            },
 
            // Adds ReturnStatement node to check whether it's useless or not.
            ReturnStatement(node) {
                if (node.argument) {
                    markReturnStatementsOnCurrentSegmentsAsUsed();
                }
                if (node.argument || astUtils.isInLoop(node) || isInFinally(node)) {
                    return;
                }
 
                for (const segment of scopeInfo.codePath.currentSegments) {
                    const info = segmentInfoMap.get(segment);
 
                    if (info) {
                        info.uselessReturns.push(node);
                        info.returned = true;
                    }
                }
                scopeInfo.uselessReturns.push(node);
            },
 
            // Registers for all statement nodes except FunctionDeclaration, BlockStatement, BreakStatement.
            // Removes return statements of the current segments from the useless return statement list.
            ClassDeclaration: markReturnStatementsOnCurrentSegmentsAsUsed,
            ContinueStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            DebuggerStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            DoWhileStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            EmptyStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            ExpressionStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            ForInStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            ForOfStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            ForStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            IfStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            ImportDeclaration: markReturnStatementsOnCurrentSegmentsAsUsed,
            LabeledStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            SwitchStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            ThrowStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            TryStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            VariableDeclaration: markReturnStatementsOnCurrentSegmentsAsUsed,
            WhileStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            WithStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            ExportNamedDeclaration: markReturnStatementsOnCurrentSegmentsAsUsed,
            ExportDefaultDeclaration: markReturnStatementsOnCurrentSegmentsAsUsed,
            ExportAllDeclaration: markReturnStatementsOnCurrentSegmentsAsUsed
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-var.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-var.js

Statements: 22.22% (16 / 72)      Branches: 0% (0 / 49)      Functions: 0% (0 / 16)      Lines: 22.54% (16 / 71)      Ignored: 1 statement     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319                      1                           1                           1                           1                     1       1                     1                   1                 1                     1                 1                                                 1                                                       1                                         1                                                                                                                       1                                                                               1                                                    
/**
 * @fileoverview Rule to check for the usage of var.
 * @author Jamund Ferguson
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Finds the nearest function scope or global scope walking up the scope
 * hierarchy.
 *
 * @param {escope.Scope} scope - The scope to traverse.
 * @returns {escope.Scope} a function scope or global scope containing the given
 *      scope.
 */
function getEnclosingFunctionScope(scope) {
    while (scope.type !== "function" && scope.type !== "global") {
        scope = scope.upper;
    }
    return scope;
}
 
/**
 * Checks whether the given variable has any references from a more specific
 * function expression (i.e. a closure).
 *
 * @param {escope.Variable} variable - A variable to check.
 * @returns {boolean} `true` if the variable is used from a closure.
 */
function isReferencedInClosure(variable) {
    const enclosingFunctionScope = getEnclosingFunctionScope(variable.scope);
 
    return variable.references.some(reference =>
        getEnclosingFunctionScope(reference.from) !== enclosingFunctionScope);
}
 
/**
 * Checks whether the given node is the assignee of a loop.
 *
 * @param {ASTNode} node - A VariableDeclaration node to check.
 * @returns {boolean} `true` if the declaration is assigned as part of loop
 *      iteration.
 */
function isLoopAssignee(node) {
    return (node.parent.type === "ForOfStatement" || node.parent.type === "ForInStatement") &&
        node === node.parent.left;
}
 
/**
 * Checks whether the given variable declaration is immediately initialized.
 *
 * @param {ASTNode} node - A VariableDeclaration node to check.
 * @returns {boolean} `true` if the declaration has an initializer.
 */
function isDeclarationInitialized(node) {
    return node.declarations.every(declarator => declarator.init !== null);
}
 
const SCOPE_NODE_TYPE = /^(?:Program|BlockStatement|SwitchStatement|ForStatement|ForInStatement|ForOfStatement)$/;
 
/**
 * Gets the scope node which directly contains a given node.
 *
 * @param {ASTNode} node - A node to get. This is a `VariableDeclaration` or
 *      an `Identifier`.
 * @returns {ASTNode} A scope node. This is one of `Program`, `BlockStatement`,
 *      `SwitchStatement`, `ForStatement`, `ForInStatement`, and
 *      `ForOfStatement`.
 */
function getScopeNode(node) {
    while (node) {
        if (SCOPE_NODE_TYPE.test(node.type)) {
            return node;
        }
 
        node = node.parent;
    }
 
    /* istanbul ignore next : unreachable */
    return null;
}
 
/**
 * Checks whether a given variable is redeclared or not.
 *
 * @param {escope.Variable} variable - A variable to check.
 * @returns {boolean} `true` if the variable is redeclared.
 */
function isRedeclared(variable) {
    return variable.defs.length >= 2;
}
 
/**
 * Checks whether a given variable is used from outside of the specified scope.
 *
 * @param {ASTNode} scopeNode - A scope node to check.
 * @returns {Function} The predicate function which checks whether a given
 *      variable is used from outside of the specified scope.
 */
function isUsedFromOutsideOf(scopeNode) {
 
    /**
     * Checks whether a given reference is inside of the specified scope or not.
     *
     * @param {escope.Reference} reference - A reference to check.
     * @returns {boolean} `true` if the reference is inside of the specified
     *      scope.
     */
    function isOutsideOfScope(reference) {
        const scope = scopeNode.range;
        const id = reference.identifier.range;
 
        return id[0] < scope[0] || id[1] > scope[1];
    }
 
    return function(variable) {
        return variable.references.some(isOutsideOfScope);
    };
}
 
/**
 * Creates the predicate function which checks whether a variable has their references in TDZ.
 *
 * The predicate function would return `true`:
 *
 * - if a reference is before the declarator. E.g. (var a = b, b = 1;)(var {a = b, b} = {};)
 * - if a reference is in the expression of their default value.  E.g. (var {a = a} = {};)
 * - if a reference is in the expression of their initializer.  E.g. (var a = a;)
 *
 * @param {ASTNode} node - The initializer node of VariableDeclarator.
 * @returns {Function} The predicate function.
 * @private
 */
function hasReferenceInTDZ(node) {
    const initStart = node.range[0];
    const initEnd = node.range[1];
 
    return variable => {
        const id = variable.defs[0].name;
        const idStart = id.range[0];
        const defaultValue = (id.parent.type === "AssignmentPattern" ? id.parent.right : null);
        const defaultStart = defaultValue && defaultValue.range[0];
        const defaultEnd = defaultValue && defaultValue.range[1];
 
        return variable.references.some(reference => {
            const start = reference.identifier.range[0];
            const end = reference.identifier.range[1];
 
            return !reference.init && (
                start < idStart ||
                (defaultValue !== null && start >= defaultStart && end <= defaultEnd) ||
                (start >= initStart && end <= initEnd)
            );
        });
    };
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require `let` or `const` instead of `var`",
            category: "ECMAScript 6",
            recommended: false
        },
 
        schema: [],
        fixable: "code"
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        /**
         * Checks whether the variables which are defined by the given declarator node have their references in TDZ.
         *
         * @param {ASTNode} declarator - The VariableDeclarator node to check.
         * @returns {boolean} `true` if one of the variables which are defined by the given declarator node have their references in TDZ.
         */
        function hasSelfReferenceInTDZ(declarator) {
            if (!declarator.init) {
                return false;
            }
            const variables = context.getDeclaredVariables(declarator);
 
            return variables.some(hasReferenceInTDZ(declarator.init));
        }
 
        /**
         * Checks whether it can fix a given variable declaration or not.
         * It cannot fix if the following cases:
         *
         * - A variable is declared on a SwitchCase node.
         * - A variable is redeclared.
         * - A variable is used from outside the scope.
         * - A variable is used from a closure within a loop.
         * - A variable might be used before it is assigned within a loop.
         * - A variable might be used in TDZ.
         * - A variable is declared in statement position (e.g. a single-line `IfStatement`)
         *
         * ## A variable is declared on a SwitchCase node.
         *
         * If this rule modifies 'var' declarations on a SwitchCase node, it
         * would generate the warnings of 'no-case-declarations' rule. And the
         * 'eslint:recommended' preset includes 'no-case-declarations' rule, so
         * this rule doesn't modify those declarations.
         *
         * ## A variable is redeclared.
         *
         * The language spec disallows redeclarations of `let` declarations.
         * Those variables would cause syntax errors.
         *
         * ## A variable is used from outside the scope.
         *
         * The language spec disallows accesses from outside of the scope for
         * `let` declarations. Those variables would cause reference errors.
         *
         * ## A variable is used from a closure within a loop.
         *
         * A `var` declaration within a loop shares the same variable instance
         * across all loop iterations, while a `let` declaration creates a new
         * instance for each iteration. This means if a variable in a loop is
         * referenced by any closure, changing it from `var` to `let` would
         * change the behavior in a way that is generally unsafe.
         *
         * ## A variable might be used before it is assigned within a loop.
         *
         * Within a loop, a `let` declaration without an initializer will be
         * initialized to null, while a `var` declaration will retain its value
         * from the previous iteration, so it is only safe to change `var` to
         * `let` if we can statically determine that the variable is always
         * assigned a value before its first access in the loop body. To keep
         * the implementation simple, we only convert `var` to `let` within
         * loops when the variable is a loop assignee or the declaration has an
         * initializer.
         *
         * @param {ASTNode} node - A variable declaration node to check.
         * @returns {boolean} `true` if it can fix the node.
         */
        function canFix(node) {
            const variables = context.getDeclaredVariables(node);
            const scopeNode = getScopeNode(node);
 
            if (node.parent.type === "SwitchCase" ||
                node.declarations.some(hasSelfReferenceInTDZ) ||
                variables.some(isRedeclared) ||
                variables.some(isUsedFromOutsideOf(scopeNode))
            ) {
                return false;
            }
 
            if (astUtils.isInLoop(node)) {
                if (variables.some(isReferencedInClosure)) {
                    return false;
                }
                if (!isLoopAssignee(node) && !isDeclarationInitialized(node)) {
                    return false;
                }
            }
 
            if (
                !isLoopAssignee(node) &&
                !(node.parent.type === "ForStatement" && node.parent.init === node) &&
                !astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type)
            ) {
 
                // If the declaration is not in a block, e.g. `if (foo) var bar = 1;`, then it can't be fixed.
                return false;
            }
 
            return true;
        }
 
        /**
         * Reports a given variable declaration node.
         *
         * @param {ASTNode} node - A variable declaration node to report.
         * @returns {void}
         */
        function report(node) {
            const varToken = sourceCode.getFirstToken(node);
 
            context.report({
                node,
                message: "Unexpected var, use let or const instead.",
 
                fix(fixer) {
                    if (canFix(node)) {
                        return fixer.replaceText(varToken, "let");
                    }
                    return null;
                }
            });
        }
 
        return {
            "VariableDeclaration:exit"(node) {
                if (node.kind === "var") {
                    report(node);
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-void.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-void.js

Statements: 25% (1 / 4)      Branches: 0% (0 / 2)      Functions: 0% (0 / 2)      Lines: 25% (1 / 4)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39                    1                                                        
/**
 * @fileoverview Rule to disallow use of void operator.
 * @author Mike Sidorov
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `void` operators",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            UnaryExpression(node) {
                if (node.operator === "void") {
                    context.report({ node, message: "Expected 'undefined' and instead saw 'void'." });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-warning-comments.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-warning-comments.js

Statements: 18.52% (5 / 27)      Branches: 0% (0 / 18)      Functions: 0% (0 / 4)      Lines: 18.52% (5 / 27)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137              1           1                                                                                   1                                                                             1                                 1                                                  
/**
 * @fileoverview Rule that warns about used warning comments
 * @author Alexander Schmidt <https://github.com/lxanders>
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow specified warning terms in comments",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    terms: {
                        type: "array",
                        items: {
                            type: "string"
                        }
                    },
                    location: {
                        enum: ["start", "anywhere"]
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        const configuration = context.options[0] || {},
            warningTerms = configuration.terms || ["todo", "fixme", "xxx"],
            location = configuration.location || "start",
            selfConfigRegEx = /\bno-warning-comments\b/;
 
        /**
         * Convert a warning term into a RegExp which will match a comment containing that whole word in the specified
         * location ("start" or "anywhere"). If the term starts or ends with non word characters, then the match will not
         * require word boundaries on that side.
         *
         * @param {string} term A term to convert to a RegExp
         * @returns {RegExp} The term converted to a RegExp
         */
        function convertToRegExp(term) {
            const escaped = term.replace(/[-/\\$^*+?.()|[\]{}]/g, "\\$&");
            let prefix;
 
            /*
             * If the term ends in a word character (a-z0-9_), ensure a word
             * boundary at the end, so that substrings do not get falsely
             * matched. eg "todo" in a string such as "mastodon".
             * If the term ends in a non-word character, then \b won't match on
             * the boundary to the next non-word character, which would likely
             * be a space. For example `/\bFIX!\b/.test('FIX! blah') === false`.
             * In these cases, use no bounding match. Same applies for the
             * prefix, handled below.
             */
            const suffix = /\w$/.test(term) ? "\\b" : "";
 
            if (location === "start") {
 
                /*
                 * When matching at the start, ignore leading whitespace, and
                 * there's no need to worry about word boundaries.
                 */
                prefix = "^\\s*";
            } else if (/^\w/.test(term)) {
                prefix = "\\b";
            } else {
                prefix = "";
            }
 
            return new RegExp(prefix + escaped + suffix, "i");
        }
 
        const warningRegExps = warningTerms.map(convertToRegExp);
 
        /**
         * Checks the specified comment for matches of the configured warning terms and returns the matches.
         * @param {string} comment The comment which is checked.
         * @returns {Array} All matched warning terms for this comment.
         */
        function commentContainsWarningTerm(comment) {
            const matches = [];
 
            warningRegExps.forEach((regex, index) => {
                if (regex.test(comment)) {
                    matches.push(warningTerms[index]);
                }
            });
 
            return matches;
        }
 
        /**
         * Checks the specified node for matching warning comments and reports them.
         * @param {ASTNode} node The AST node being checked.
         * @returns {void} undefined.
         */
        function checkComment(node) {
            if (astUtils.isDirectiveComment(node) && selfConfigRegEx.test(node.value)) {
                return;
            }
 
            const matches = commentContainsWarningTerm(node.value);
 
            matches.forEach(matchedTerm => {
                context.report({
                    node,
                    message: "Unexpected '{{matchedTerm}}' comment.",
                    data: {
                        matchedTerm
                    }
                });
            });
        }
 
        return {
            BlockComment: checkComment,
            LineComment: checkComment
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-whitespace-before-property.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-whitespace-before-property.js

Statements: 14.29% (3 / 21)      Branches: 0% (0 / 12)      Functions: 0% (0 / 4)      Lines: 14.29% (3 / 21)      Ignored: none     

All files » node-npmtest-eslint/node_modules/eslint/lib/rules/ » no-whitespace-before-property.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94                    1           1                                                     1                                                                                                    
/**
 * @fileoverview Rule to disallow whitespace before properties
 * @author Kai Cataldo
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow whitespace before properties",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
        schema: []
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Reports whitespace before property token
         * @param {ASTNode} node - the node to report in the event of an error
         * @param {Token} leftToken - the left token
         * @param {Token} rightToken - the right token
         * @returns {void}
         * @private
         */
        function reportError(node, leftToken, rightToken) {
            const replacementText = node.computed ? "" : ".";
 
            context.report({
                node,
                message: "Unexpected whitespace before property {{propName}}.",
                data: {
                    propName: sourceCode.getText(node.property)
                },
                fix(fixer) {
                    if (!node.computed && astUtils.isDecimalInteger(node.object)) {
 
                        // If the object is a number literal, fixing it to something like 5.toString() would cause a SyntaxError.
                        // Don't fix this case.
                        return null;
                    }
                    return fixer.replaceTextRange([leftToken.range[1], rightToken.range[0]], replacementText);
                }
            });
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            MemberExpression(node) {
                let rightToken;
                let leftToken;
 
                if (!astUtils.isTokenOnSameLine(node.object, node.property)) {
                    return;
                }
 
                if (node.computed) {
                    rightToken = sourceCode.getTokenBefore(node.property, astUtils.isOpeningBracketToken);
                    leftToken = sourceCode.getTokenBefore(rightToken);
                } else {
                    rightToken = sourceCode.getFirstToken(node.property);
                    leftToken = sourceCode.getTokenBefore(rightToken, 1);
                }
 
                if (sourceCode.isSpaceBetweenTokens(leftToken, rightToken)) {
                    reportError(node, leftToken, rightToken);
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-with.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/no-with.js

Statements: 33.33% (1 / 3)      Branches: 100% (0 / 0)      Functions: 0% (0 / 2)      Lines: 33.33% (1 / 3)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34                      1                                            
/**
 * @fileoverview Rule to flag use of with statement
 * @author Nicholas C. Zakas
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `with` statements",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
            WithStatement(node) {
                context.report({ node, message: "Unexpected use of 'with' statement." });
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/nonblock-statement-body-position.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/nonblock-statement-body-position.js

Statements: 14.81% (4 / 27)      Branches: 0% (0 / 23)      Functions: 0% (0 / 5)      Lines: 14.81% (4 / 27)      Ignored: none     

All files » node-npmtest-eslint/node_modules/eslint/lib/rules/ » nonblock-statement-body-position.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116                    1   1                                                                               1                       1                                                                                                      
/**
 * @fileoverview enforce the location of single-line statements
 * @author Teddy Katz
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
const POSITION_SCHEMA = { enum: ["beside", "below", "any"] };
 
module.exports = {
    meta: {
        docs: {
            description: "enforce the location of single-line statements",
            category: "Stylistic Issues",
            recommended: false
        },
        fixable: "whitespace",
        schema: [
            POSITION_SCHEMA,
            {
                properties: {
                    overrides: {
                        properties: {
                            if: POSITION_SCHEMA,
                            else: POSITION_SCHEMA,
                            while: POSITION_SCHEMA,
                            do: POSITION_SCHEMA,
                            for: POSITION_SCHEMA
                        },
                        additionalProperties: false
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        //----------------------------------------------------------------------
        // Helpers
        //----------------------------------------------------------------------
 
        /**
         * Gets the applicable preference for a particular keyword
         * @param {string} keywordName The name of a keyword, e.g. 'if'
         * @returns {string} The applicable option for the keyword, e.g. 'beside'
         */
        function getOption(keywordName) {
            return context.options[1] && context.options[1].overrides && context.options[1].overrides[keywordName] ||
                context.options[0] ||
                "beside";
        }
 
        /**
         * Validates the location of a single-line statement
         * @param {ASTNode} node The single-line statement
         * @param {string} keywordName The applicable keyword name for the single-line statement
         * @returns {void}
         */
        function validateStatement(node, keywordName) {
            const option = getOption(keywordName);
 
            if (node.type === "BlockStatement" || option === "any") {
                return;
            }
 
            const tokenBefore = sourceCode.getTokenBefore(node);
 
            if (tokenBefore.loc.end.line === node.loc.start.line && option === "below") {
                context.report({
                    node,
                    message: "Expected a linebreak before this statement.",
                    fix: fixer => fixer.insertTextBefore(node, "\n")
                });
            } else if (tokenBefore.loc.end.line !== node.loc.start.line && option === "beside") {
                context.report({
                    node,
                    message: "Expected no linebreak before this statement.",
                    fix(fixer) {
                        if (sourceCode.getText().slice(tokenBefore.range[1], node.range[0]).trim()) {
                            return null;
                        }
                        return fixer.replaceTextRange([tokenBefore.range[1], node.range[0]], " ");
                    }
                });
            }
        }
 
        //----------------------------------------------------------------------
        // Public
        //----------------------------------------------------------------------
 
        return {
            IfStatement(node) {
                validateStatement(node.consequent, "if");
 
                // Check the `else` node, but don't check 'else if' statements.
                if (node.alternate && node.alternate.type !== "IfStatement") {
                    validateStatement(node.alternate, "else");
                }
            },
            WhileStatement: node => validateStatement(node.body, "while"),
            DoWhileStatement: node => validateStatement(node.body, "do"),
            ForStatement: node => validateStatement(node.body, "for"),
            ForInStatement: node => validateStatement(node.body, "for"),
            ForOfStatement: node => validateStatement(node.body, "for")
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/object-curly-newline.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/object-curly-newline.js

Statements: 13.33% (6 / 45)      Branches: 0% (0 / 27)      Functions: 0% (0 / 8)      Lines: 13.33% (6 / 45)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211                      1             1                                                       1                                                   1                                 1                                                                         1                                                                                                                                                                        
/**
 * @fileoverview Rule to require or disallow line breaks inside braces.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
// Schema objects.
const OPTION_VALUE = {
    oneOf: [
        {
            enum: ["always", "never"]
        },
        {
            type: "object",
            properties: {
                multiline: {
                    type: "boolean"
                },
                minProperties: {
                    type: "integer",
                    minimum: 0
                }
            },
            additionalProperties: false,
            minProperties: 1
        }
    ]
};
 
/**
 * Normalizes a given option value.
 *
 * @param {string|Object|undefined} value - An option value to parse.
 * @returns {{multiline: boolean, minProperties: number}} Normalized option object.
 */
function normalizeOptionValue(value) {
    let multiline = false;
    let minProperties = Number.POSITIVE_INFINITY;
 
    if (value) {
        if (value === "always") {
            minProperties = 0;
        } else if (value === "never") {
            minProperties = Number.POSITIVE_INFINITY;
        } else {
            multiline = Boolean(value.multiline);
            minProperties = value.minProperties || Number.POSITIVE_INFINITY;
        }
    } else {
        multiline = true;
    }
 
    return { multiline, minProperties };
}
 
/**
 * Normalizes a given option value.
 *
 * @param {string|Object|undefined} options - An option value to parse.
 * @returns {{ObjectExpression: {multiline: boolean, minProperties: number}, ObjectPattern: {multiline: boolean, minProperties: number}}} Normalized option object.
 */
function normalizeOptions(options) {
    if (options && (options.ObjectExpression || options.ObjectPattern)) {
        return {
            ObjectExpression: normalizeOptionValue(options.ObjectExpression),
            ObjectPattern: normalizeOptionValue(options.ObjectPattern)
        };
    }
 
    const value = normalizeOptionValue(options);
 
    return { ObjectExpression: value, ObjectPattern: value };
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent line breaks inside braces",
            category: "Stylistic Issues",
            recommended: false
        },
        fixable: "whitespace",
        schema: [
            {
                oneOf: [
                    OPTION_VALUE,
                    {
                        type: "object",
                        properties: {
                            ObjectExpression: OPTION_VALUE,
                            ObjectPattern: OPTION_VALUE
                        },
                        additionalProperties: false,
                        minProperties: 1
                    }
                ]
            }
        ]
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
        const normalizedOptions = normalizeOptions(context.options[0]);
 
        /**
         * Reports a given node if it violated this rule.
         *
         * @param {ASTNode} node - A node to check. This is an ObjectExpression node or an ObjectPattern node.
         * @param {{multiline: boolean, minProperties: number}} options - An option object.
         * @returns {void}
         */
        function check(node) {
            const options = normalizedOptions[node.type];
            const openBrace = sourceCode.getFirstToken(node);
            const closeBrace = sourceCode.getLastToken(node);
            let first = sourceCode.getTokenAfter(openBrace, { includeComments: true });
            let last = sourceCode.getTokenBefore(closeBrace, { includeComments: true });
            const needsLinebreaks = (
                node.properties.length >= options.minProperties ||
                (
                    options.multiline &&
                    node.properties.length > 0 &&
                    first.loc.start.line !== last.loc.end.line
                )
            );
 
            /*
             * Use tokens or comments to check multiline or not.
             * But use only tokens to check whether line breaks are needed.
             * This allows:
             *     var obj = { // eslint-disable-line foo
             *         a: 1
             *     }
             */
            first = sourceCode.getTokenAfter(openBrace);
            last = sourceCode.getTokenBefore(closeBrace);
 
            if (needsLinebreaks) {
                if (astUtils.isTokenOnSameLine(openBrace, first)) {
                    context.report({
                        message: "Expected a line break after this opening brace.",
                        node,
                        loc: openBrace.loc.start,
                        fix(fixer) {
                            return fixer.insertTextAfter(openBrace, "\n");
                        }
                    });
                }
                if (astUtils.isTokenOnSameLine(last, closeBrace)) {
                    context.report({
                        message: "Expected a line break before this closing brace.",
                        node,
                        loc: closeBrace.loc.start,
                        fix(fixer) {
                            return fixer.insertTextBefore(closeBrace, "\n");
                        }
                    });
                }
            } else {
                if (!astUtils.isTokenOnSameLine(openBrace, first)) {
                    context.report({
                        message: "Unexpected line break after this opening brace.",
                        node,
                        loc: openBrace.loc.start,
                        fix(fixer) {
                            return fixer.removeRange([
                                openBrace.range[1],
                                first.range[0]
                            ]);
                        }
                    });
                }
                if (!astUtils.isTokenOnSameLine(last, closeBrace)) {
                    context.report({
                        message: "Unexpected line break before this closing brace.",
                        node,
                        loc: closeBrace.loc.start,
                        fix(fixer) {
                            return fixer.removeRange([
                                last.range[1],
                                closeBrace.range[0]
                            ]);
                        }
                    });
                }
            }
        }
 
        return {
            ObjectExpression: check,
            ObjectPattern: check
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/object-curly-spacing.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/object-curly-spacing.js

Statements: 19.67% (12 / 61)      Branches: 0% (0 / 45)      Functions: 0% (0 / 15)      Lines: 19.67% (12 / 61)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301            1           1                                                                               1                                       1                                           1                                           1                                       1                                             1                                                                                             1                     1                                   1                                                       1                                                                          
/**
 * @fileoverview Disallows or enforces spaces inside of object literals.
 * @author Jamund Ferguson
 */
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent spacing inside braces",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                enum: ["always", "never"]
            },
            {
                type: "object",
                properties: {
                    arraysInObjects: {
                        type: "boolean"
                    },
                    objectsInObjects: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const spaced = context.options[0] === "always",
            sourceCode = context.getSourceCode();
 
        /**
         * Determines whether an option is set, relative to the spacing option.
         * If spaced is "always", then check whether option is set to false.
         * If spaced is "never", then check whether option is set to true.
         * @param {Object} option - The option to exclude.
         * @returns {boolean} Whether or not the property is excluded.
         */
        function isOptionSet(option) {
            return context.options[1] ? context.options[1][option] === !spaced : false;
        }
 
        const options = {
            spaced,
            arraysInObjectsException: isOptionSet("arraysInObjects"),
            objectsInObjectsException: isOptionSet("objectsInObjects")
        };
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
        * Reports that there shouldn't be a space after the first token
        * @param {ASTNode} node - The node to report in the event of an error.
        * @param {Token} token - The token to use for the report.
        * @returns {void}
        */
        function reportNoBeginningSpace(node, token) {
            context.report({
                node,
                loc: token.loc.start,
                message: "There should be no space after '{{token}}'.",
                data: {
                    token: token.value
                },
                fix(fixer) {
                    const nextToken = context.getSourceCode().getTokenAfter(token);
 
                    return fixer.removeRange([token.range[1], nextToken.range[0]]);
                }
            });
        }
 
        /**
        * Reports that there shouldn't be a space before the last token
        * @param {ASTNode} node - The node to report in the event of an error.
        * @param {Token} token - The token to use for the report.
        * @returns {void}
        */
        function reportNoEndingSpace(node, token) {
            context.report({
                node,
                loc: token.loc.start,
                message: "There should be no space before '{{token}}'.",
                data: {
                    token: token.value
                },
                fix(fixer) {
                    const previousToken = context.getSourceCode().getTokenBefore(token);
 
                    return fixer.removeRange([previousToken.range[1], token.range[0]]);
                }
            });
        }
 
        /**
        * Reports that there should be a space after the first token
        * @param {ASTNode} node - The node to report in the event of an error.
        * @param {Token} token - The token to use for the report.
        * @returns {void}
        */
        function reportRequiredBeginningSpace(node, token) {
            context.report({
                node,
                loc: token.loc.start,
                message: "A space is required after '{{token}}'.",
                data: {
                    token: token.value
                },
                fix(fixer) {
                    return fixer.insertTextAfter(token, " ");
                }
            });
        }
 
        /**
        * Reports that there should be a space before the last token
        * @param {ASTNode} node - The node to report in the event of an error.
        * @param {Token} token - The token to use for the report.
        * @returns {void}
        */
        function reportRequiredEndingSpace(node, token) {
            context.report({
                node,
                loc: token.loc.start,
                message: "A space is required before '{{token}}'.",
                data: {
                    token: token.value
                },
                fix(fixer) {
                    return fixer.insertTextBefore(token, " ");
                }
            });
        }
 
        /**
         * Determines if spacing in curly braces is valid.
         * @param {ASTNode} node The AST node to check.
         * @param {Token} first The first token to check (should be the opening brace)
         * @param {Token} second The second token to check (should be first after the opening brace)
         * @param {Token} penultimate The penultimate token to check (should be last before closing brace)
         * @param {Token} last The last token to check (should be closing brace)
         * @returns {void}
         */
        function validateBraceSpacing(node, first, second, penultimate, last) {
            if (astUtils.isTokenOnSameLine(first, second)) {
                const firstSpaced = sourceCode.isSpaceBetweenTokens(first, second);
 
                if (options.spaced && !firstSpaced) {
                    reportRequiredBeginningSpace(node, first);
                }
                if (!options.spaced && firstSpaced) {
                    reportNoBeginningSpace(node, first);
                }
            }
 
            if (astUtils.isTokenOnSameLine(penultimate, last)) {
                const shouldCheckPenultimate = (
                    options.arraysInObjectsException && astUtils.isClosingBracketToken(penultimate) ||
                    options.objectsInObjectsException && astUtils.isClosingBraceToken(penultimate)
                );
                const penultimateType = shouldCheckPenultimate && sourceCode.getNodeByRangeIndex(penultimate.start).type;
 
                const closingCurlyBraceMustBeSpaced = (
                    options.arraysInObjectsException && penultimateType === "ArrayExpression" ||
                    options.objectsInObjectsException && (penultimateType === "ObjectExpression" || penultimateType === "ObjectPattern")
                ) ? !options.spaced : options.spaced;
 
                const lastSpaced = sourceCode.isSpaceBetweenTokens(penultimate, last);
 
                if (closingCurlyBraceMustBeSpaced && !lastSpaced) {
                    reportRequiredEndingSpace(node, last);
                }
                if (!closingCurlyBraceMustBeSpaced && lastSpaced) {
                    reportNoEndingSpace(node, last);
                }
            }
        }
 
        /**
         * Gets '}' token of an object node.
         *
         * Because the last token of object patterns might be a type annotation,
         * this traverses tokens preceded by the last property, then returns the
         * first '}' token.
         *
         * @param {ASTNode} node - The node to get. This node is an
         *      ObjectExpression or an ObjectPattern. And this node has one or
         *      more properties.
         * @returns {Token} '}' token.
         */
        function getClosingBraceOfObject(node) {
            const lastProperty = node.properties[node.properties.length - 1];
 
            return sourceCode.getTokenAfter(lastProperty, astUtils.isClosingBraceToken);
        }
 
        /**
         * Reports a given object node if spacing in curly braces is invalid.
         * @param {ASTNode} node - An ObjectExpression or ObjectPattern node to check.
         * @returns {void}
         */
        function checkForObject(node) {
            if (node.properties.length === 0) {
                return;
            }
 
            const first = sourceCode.getFirstToken(node),
                last = getClosingBraceOfObject(node),
                second = sourceCode.getTokenAfter(first),
                penultimate = sourceCode.getTokenBefore(last);
 
            validateBraceSpacing(node, first, second, penultimate, last);
        }
 
        /**
         * Reports a given import node if spacing in curly braces is invalid.
         * @param {ASTNode} node - An ImportDeclaration node to check.
         * @returns {void}
         */
        function checkForImport(node) {
            if (node.specifiers.length === 0) {
                return;
            }
 
            let firstSpecifier = node.specifiers[0];
            const lastSpecifier = node.specifiers[node.specifiers.length - 1];
 
            if (lastSpecifier.type !== "ImportSpecifier") {
                return;
            }
            if (firstSpecifier.type !== "ImportSpecifier") {
                firstSpecifier = node.specifiers[1];
            }
 
            const first = sourceCode.getTokenBefore(firstSpecifier),
                last = sourceCode.getTokenAfter(lastSpecifier, astUtils.isNotCommaToken),
                second = sourceCode.getTokenAfter(first),
                penultimate = sourceCode.getTokenBefore(last);
 
            validateBraceSpacing(node, first, second, penultimate, last);
        }
 
        /**
         * Reports a given export node if spacing in curly braces is invalid.
         * @param {ASTNode} node - An ExportNamedDeclaration node to check.
         * @returns {void}
         */
        function checkForExport(node) {
            if (node.specifiers.length === 0) {
                return;
            }
 
            const firstSpecifier = node.specifiers[0],
                lastSpecifier = node.specifiers[node.specifiers.length - 1],
                first = sourceCode.getTokenBefore(firstSpecifier),
                last = sourceCode.getTokenAfter(lastSpecifier, astUtils.isNotCommaToken),
                second = sourceCode.getTokenAfter(first),
                penultimate = sourceCode.getTokenBefore(last);
 
            validateBraceSpacing(node, first, second, penultimate, last);
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
 
            // var {x} = y;
            ObjectPattern: checkForObject,
 
            // var y = {x: 'y'}
            ObjectExpression: checkForObject,
 
            // import {y} from 'x';
            ImportDeclaration: checkForImport,
 
            // export {name} from 'yo';
            ExportNamedDeclaration: checkForExport
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/object-property-newline.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/object-property-newline.js

Statements: 4.76% (1 / 21)      Branches: 0% (0 / 14)      Functions: 0% (0 / 3)      Lines: 4.76% (1 / 21)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86                      1                                                                                                                                                    
/**
 * @fileoverview Rule to enforce placing object properties on separate lines.
 * @author Vitor Balocco
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce placing object properties on separate lines",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    allowMultiplePropertiesPerLine: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ],
 
        fixable: "whitespace"
    },
 
    create(context) {
        const allowSameLine = context.options[0] && Boolean(context.options[0].allowMultiplePropertiesPerLine);
        const errorMessage = allowSameLine
            ? "Object properties must go on a new line if they aren't all on the same line."
            : "Object properties must go on a new line.";
 
        const sourceCode = context.getSourceCode();
 
        return {
            ObjectExpression(node) {
                if (allowSameLine) {
                    if (node.properties.length > 1) {
                        const firstTokenOfFirstProperty = sourceCode.getFirstToken(node.properties[0]);
                        const lastTokenOfLastProperty = sourceCode.getLastToken(node.properties[node.properties.length - 1]);
 
                        if (firstTokenOfFirstProperty.loc.end.line === lastTokenOfLastProperty.loc.start.line) {
 
                            // All keys and values are on the same line
                            return;
                        }
                    }
                }
 
                for (let i = 1; i < node.properties.length; i++) {
                    const lastTokenOfPreviousProperty = sourceCode.getLastToken(node.properties[i - 1]);
                    const firstTokenOfCurrentProperty = sourceCode.getFirstToken(node.properties[i]);
 
                    if (lastTokenOfPreviousProperty.loc.end.line === firstTokenOfCurrentProperty.loc.start.line) {
                        context.report({
                            node,
                            loc: firstTokenOfCurrentProperty.loc.start,
                            message: errorMessage,
                            fix(fixer) {
                                const comma = sourceCode.getTokenBefore(firstTokenOfCurrentProperty);
                                const rangeAfterComma = [comma.range[1], firstTokenOfCurrentProperty.range[0]];
 
                                // Don't perform a fix if there are any comments between the comma and the next property.
                                if (sourceCode.text.slice(rangeAfterComma[0], rangeAfterComma[1]).trim()) {
                                    return null;
                                }
 
                                return fixer.replaceTextRange(rangeAfterComma, "\n");
                            }
                        });
                    }
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/object-shorthand.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/object-shorthand.js

Statements: 10.69% (14 / 131)      Branches: 0% (0 / 127)      Functions: 0% (0 / 20)      Lines: 11.38% (14 / 123)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444              1                       1         1                                                                                                                                                                                           1                       1                 1                   1                       1                                     1                                                                       1                                                                               1                                                                   1                     1                 1                                                                                                                                                                                                                                                                          
/**
 * @fileoverview Rule to enforce concise object methods and properties.
 * @author Jamund Ferguson
 */
 
"use strict";
 
const OPTIONS = {
    always: "always",
    never: "never",
    methods: "methods",
    properties: "properties",
    consistent: "consistent",
    consistentAsNeeded: "consistent-as-needed"
};
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
    meta: {
        docs: {
            description: "require or disallow method and property shorthand syntax for object literals",
            category: "ECMAScript 6",
            recommended: false
        },
 
        fixable: "code",
 
        schema: {
            anyOf: [
                {
                    type: "array",
                    items: [
                        {
                            enum: ["always", "methods", "properties", "never", "consistent", "consistent-as-needed"]
                        }
                    ],
                    minItems: 0,
                    maxItems: 1
                },
                {
                    type: "array",
                    items: [
                        {
                            enum: ["always", "methods", "properties"]
                        },
                        {
                            type: "object",
                            properties: {
                                avoidQuotes: {
                                    type: "boolean"
                                }
                            },
                            additionalProperties: false
                        }
                    ],
                    minItems: 0,
                    maxItems: 2
                },
                {
                    type: "array",
                    items: [
                        {
                            enum: ["always", "methods"]
                        },
                        {
                            type: "object",
                            properties: {
                                ignoreConstructors: {
                                    type: "boolean"
                                },
                                avoidQuotes: {
                                    type: "boolean"
                                },
                                avoidExplicitReturnArrows: {
                                    type: "boolean"
                                }
                            },
                            additionalProperties: false
                        }
                    ],
                    minItems: 0,
                    maxItems: 2
                }
            ]
        }
    },
 
    create(context) {
        const APPLY = context.options[0] || OPTIONS.always;
        const APPLY_TO_METHODS = APPLY === OPTIONS.methods || APPLY === OPTIONS.always;
        const APPLY_TO_PROPS = APPLY === OPTIONS.properties || APPLY === OPTIONS.always;
        const APPLY_NEVER = APPLY === OPTIONS.never;
        const APPLY_CONSISTENT = APPLY === OPTIONS.consistent;
        const APPLY_CONSISTENT_AS_NEEDED = APPLY === OPTIONS.consistentAsNeeded;
 
        const PARAMS = context.options[1] || {};
        const IGNORE_CONSTRUCTORS = PARAMS.ignoreConstructors;
        const AVOID_QUOTES = PARAMS.avoidQuotes;
        const AVOID_EXPLICIT_RETURN_ARROWS = !!PARAMS.avoidExplicitReturnArrows;
        const sourceCode = context.getSourceCode();
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Determines if the first character of the name is a capital letter.
         * @param {string} name The name of the node to evaluate.
         * @returns {boolean} True if the first character of the property name is a capital letter, false if not.
         * @private
         */
        function isConstructor(name) {
            const firstChar = name.charAt(0);
 
            return firstChar === firstChar.toUpperCase();
        }
 
        /**
         * Determines if the property can have a shorthand form.
         * @param {ASTNode} property Property AST node
         * @returns {boolean} True if the property can have a shorthand form
         * @private
         **/
        function canHaveShorthand(property) {
            return (property.kind !== "set" && property.kind !== "get" && property.type !== "SpreadProperty" && property.type !== "ExperimentalSpreadProperty");
        }
 
        /**
          * Checks whether a node is a string literal.
          * @param   {ASTNode} node - Any AST node.
          * @returns {boolean} `true` if it is a string literal.
          */
        function isStringLiteral(node) {
            return node.type === "Literal" && typeof node.value === "string";
        }
 
        /**
         * Determines if the property is a shorthand or not.
         * @param {ASTNode} property Property AST node
         * @returns {boolean} True if the property is considered shorthand, false if not.
         * @private
         **/
        function isShorthand(property) {
 
            // property.method is true when `{a(){}}`.
            return (property.shorthand || property.method);
        }
 
        /**
         * Determines if the property's key and method or value are named equally.
         * @param {ASTNode} property Property AST node
         * @returns {boolean} True if the key and value are named equally, false if not.
         * @private
         **/
        function isRedundant(property) {
            const value = property.value;
 
            if (value.type === "FunctionExpression") {
                return !value.id; // Only anonymous should be shorthand method.
            }
            if (value.type === "Identifier") {
                return astUtils.getStaticPropertyName(property) === value.name;
            }
 
            return false;
        }
 
        /**
         * Ensures that an object's properties are consistently shorthand, or not shorthand at all.
         * @param   {ASTNode} node Property AST node
         * @param   {boolean} checkRedundancy Whether to check longform redundancy
         * @returns {void}
         **/
        function checkConsistency(node, checkRedundancy) {
 
            // We are excluding getters/setters and spread properties as they are considered neither longform nor shorthand.
            const properties = node.properties.filter(canHaveShorthand);
 
            // Do we still have properties left after filtering the getters and setters?
            if (properties.length > 0) {
                const shorthandProperties = properties.filter(isShorthand);
 
                // If we do not have an equal number of longform properties as
                // shorthand properties, we are using the annotations inconsistently
                if (shorthandProperties.length !== properties.length) {
 
                    // We have at least 1 shorthand property
                    if (shorthandProperties.length > 0) {
                        context.report({ node, message: "Unexpected mix of shorthand and non-shorthand properties." });
                    } else if (checkRedundancy) {
 
                        // If all properties of the object contain a method or value with a name matching it's key,
                        // all the keys are redundant.
                        const canAlwaysUseShorthand = properties.every(isRedundant);
 
                        if (canAlwaysUseShorthand) {
                            context.report({ node, message: "Expected shorthand for all properties." });
                        }
                    }
                }
            }
        }
 
        /**
        * Fixes a FunctionExpression node by making it into a shorthand property.
        * @param {SourceCodeFixer} fixer The fixer object
        * @param {ASTNode} node A `Property` node that has a `FunctionExpression` or `ArrowFunctionExpression` as its value
        * @returns {Object} A fix for this node
        */
        function makeFunctionShorthand(fixer, node) {
            const firstKeyToken = node.computed ? sourceCode.getFirstToken(node, astUtils.isOpeningBracketToken) : sourceCode.getFirstToken(node.key);
            const lastKeyToken = node.computed ? sourceCode.getFirstTokenBetween(node.key, node.value, astUtils.isClosingBracketToken) : sourceCode.getLastToken(node.key);
            const keyText = sourceCode.text.slice(firstKeyToken.range[0], lastKeyToken.range[1]);
            let keyPrefix = "";
 
            if (node.value.generator) {
                keyPrefix = "*";
            } else if (node.value.async) {
                keyPrefix = "async ";
            }
 
            if (node.value.type === "FunctionExpression") {
                const functionToken = sourceCode.getTokens(node.value).find(token => token.type === "Keyword" && token.value === "function");
                const tokenBeforeParams = node.value.generator ? sourceCode.getTokenAfter(functionToken) : functionToken;
 
                return fixer.replaceTextRange(
                    [firstKeyToken.range[0], node.range[1]],
                    keyPrefix + keyText + sourceCode.text.slice(tokenBeforeParams.range[1], node.value.range[1])
                );
            }
            const arrowToken = sourceCode.getTokens(node.value).find(token => token.value === "=>");
            const tokenBeforeArrow = sourceCode.getTokenBefore(arrowToken);
            const hasParensAroundParameters = tokenBeforeArrow.type === "Punctuator" && tokenBeforeArrow.value === ")";
            const oldParamText = sourceCode.text.slice(sourceCode.getFirstToken(node.value, node.value.async ? 1 : 0).range[0], tokenBeforeArrow.range[1]);
            const newParamText = hasParensAroundParameters ? oldParamText : `(${oldParamText})`;
 
            return fixer.replaceTextRange(
                [firstKeyToken.range[0], node.range[1]],
                keyPrefix + keyText + newParamText + sourceCode.text.slice(arrowToken.range[1], node.value.range[1])
            );
 
        }
 
        /**
        * Fixes a FunctionExpression node by making it into a longform property.
        * @param {SourceCodeFixer} fixer The fixer object
        * @param {ASTNode} node A `Property` node that has a `FunctionExpression` as its value
        * @returns {Object} A fix for this node
        */
        function makeFunctionLongform(fixer, node) {
            const firstKeyToken = node.computed ? sourceCode.getTokens(node).find(token => token.value === "[") : sourceCode.getFirstToken(node.key);
            const lastKeyToken = node.computed ? sourceCode.getTokensBetween(node.key, node.value).find(token => token.value === "]") : sourceCode.getLastToken(node.key);
            const keyText = sourceCode.text.slice(firstKeyToken.range[0], lastKeyToken.range[1]);
            let functionHeader = "function";
 
            if (node.value.generator) {
                functionHeader = "function*";
            } else if (node.value.async) {
                functionHeader = "async function";
            }
 
            return fixer.replaceTextRange([node.range[0], lastKeyToken.range[1]], `${keyText}: ${functionHeader}`);
        }
 
        /*
         * To determine whether a given arrow function has a lexical identifier (`this`, `arguments`, `super`, or `new.target`),
         * create a stack of functions that define these identifiers (i.e. all functions except arrow functions) as the AST is
         * traversed. Whenever a new function is encountered, create a new entry on the stack (corresponding to a different lexical
         * scope of `this`), and whenever a function is exited, pop that entry off the stack. When an arrow function is entered,
         * keep a reference to it on the current stack entry, and remove that reference when the arrow function is exited.
         * When a lexical identifier is encountered, mark all the arrow functions on the current stack entry by adding them
         * to an `arrowsWithLexicalIdentifiers` set. Any arrow function in that set will not be reported by this rule,
         * because converting it into a method would change the value of one of the lexical identifiers.
         */
        const lexicalScopeStack = [];
        const arrowsWithLexicalIdentifiers = new WeakSet();
        const argumentsIdentifiers = new WeakSet();
 
        /**
        * Enters a function. This creates a new lexical identifier scope, so a new Set of arrow functions is pushed onto the stack.
        * Also, this marks all `arguments` identifiers so that they can be detected later.
        * @returns {void}
        */
        function enterFunction() {
            lexicalScopeStack.unshift(new Set());
            context.getScope().variables.filter(variable => variable.name === "arguments").forEach(variable => {
                variable.references.map(ref => ref.identifier).forEach(identifier => argumentsIdentifiers.add(identifier));
            });
        }
 
        /**
        * Exits a function. This pops the current set of arrow functions off the lexical scope stack.
        * @returns {void}
        */
        function exitFunction() {
            lexicalScopeStack.shift();
        }
 
        /**
        * Marks the current function as having a lexical keyword. This implies that all arrow functions
        * in the current lexical scope contain a reference to this lexical keyword.
        * @returns {void}
        */
        function reportLexicalIdentifier() {
            lexicalScopeStack[0].forEach(arrowFunction => arrowsWithLexicalIdentifiers.add(arrowFunction));
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            Program: enterFunction,
            FunctionDeclaration: enterFunction,
            FunctionExpression: enterFunction,
            "Program:exit": exitFunction,
            "FunctionDeclaration:exit": exitFunction,
            "FunctionExpression:exit": exitFunction,
 
            ArrowFunctionExpression(node) {
                lexicalScopeStack[0].add(node);
            },
            "ArrowFunctionExpression:exit"(node) {
                lexicalScopeStack[0].delete(node);
            },
 
            ThisExpression: reportLexicalIdentifier,
            Super: reportLexicalIdentifier,
            MetaProperty(node) {
                if (node.meta.name === "new" && node.property.name === "target") {
                    reportLexicalIdentifier();
                }
            },
            Identifier(node) {
                if (argumentsIdentifiers.has(node)) {
                    reportLexicalIdentifier();
                }
            },
 
            ObjectExpression(node) {
                if (APPLY_CONSISTENT) {
                    checkConsistency(node, false);
                } else if (APPLY_CONSISTENT_AS_NEEDED) {
                    checkConsistency(node, true);
                }
            },
 
            "Property:exit"(node) {
                const isConciseProperty = node.method || node.shorthand;
 
                // Ignore destructuring assignment
                if (node.parent.type === "ObjectPattern") {
                    return;
                }
 
                // getters and setters are ignored
                if (node.kind === "get" || node.kind === "set") {
                    return;
                }
 
                // only computed methods can fail the following checks
                if (node.computed && node.value.type !== "FunctionExpression" && node.value.type !== "ArrowFunctionExpression") {
                    return;
                }
 
                //--------------------------------------------------------------
                // Checks for property/method shorthand.
                if (isConciseProperty) {
                    if (node.method && (APPLY_NEVER || AVOID_QUOTES && isStringLiteral(node.key))) {
                        const message = APPLY_NEVER ? "Expected longform method syntax." : "Expected longform method syntax for string literal keys.";
 
                        // { x() {} } should be written as { x: function() {} }
                        context.report({
                            node,
                            message,
                            fix: fixer => makeFunctionLongform(fixer, node)
                        });
                    } else if (APPLY_NEVER) {
 
                        // { x } should be written as { x: x }
                        context.report({
                            node,
                            message: "Expected longform property syntax.",
                            fix: fixer => fixer.insertTextAfter(node.key, `: ${node.key.name}`)
                        });
                    }
                } else if (APPLY_TO_METHODS && !node.value.id && (node.value.type === "FunctionExpression" || node.value.type === "ArrowFunctionExpression")) {
                    if (IGNORE_CONSTRUCTORS && isConstructor(node.key.name)) {
                        return;
                    }
                    if (AVOID_QUOTES && isStringLiteral(node.key)) {
                        return;
                    }
 
                    // {[x]: function(){}} should be written as {[x]() {}}
                    if (node.value.type === "FunctionExpression" ||
                        node.value.type === "ArrowFunctionExpression" &&
                        node.value.body.type === "BlockStatement" &&
                        AVOID_EXPLICIT_RETURN_ARROWS &&
                        !arrowsWithLexicalIdentifiers.has(node.value)
                    ) {
                        context.report({
                            node,
                            message: "Expected method shorthand.",
                            fix: fixer => makeFunctionShorthand(fixer, node)
                        });
                    }
                } else if (node.value.type === "Identifier" && node.key.name === node.value.name && APPLY_TO_PROPS) {
 
                    // {x: x} should be written as {x}
                    context.report({
                        node,
                        message: "Expected property shorthand.",
                        fix(fixer) {
                            return fixer.replaceText(node, node.value.name);
                        }
                    });
                } else if (node.value.type === "Identifier" && node.key.type === "Literal" && node.key.value === node.value.name && APPLY_TO_PROPS) {
                    if (AVOID_QUOTES) {
                        return;
                    }
 
                    // {"x": x} should be written as {x}
                    context.report({
                        node,
                        message: "Expected property shorthand.",
                        fix(fixer) {
                            return fixer.replaceText(node, node.value.name);
                        }
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/one-var-declaration-per-line.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/one-var-declaration-per-line.js

Statements: 17.65% (3 / 17)      Branches: 0% (0 / 14)      Functions: 0% (0 / 3)      Lines: 17.65% (3 / 17)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88                    1                                                                 1                   1                                                                    
/**
 * @fileoverview Rule to check multiple var declarations per line
 * @author Alberto Rodríguez
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require or disallow newlines around variable declarations",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                enum: ["always", "initializations"]
            }
        ],
 
        fixable: "whitespace"
    },
 
    create(context) {
 
        const ERROR_MESSAGE = "Expected variable declaration to be on a new line.";
        const always = context.options[0] === "always";
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
 
        /**
         * Determine if provided keyword is a variant of for specifiers
         * @private
         * @param {string} keyword - keyword to test
         * @returns {boolean} True if `keyword` is a variant of for specifier
         */
        function isForTypeSpecifier(keyword) {
            return keyword === "ForStatement" || keyword === "ForInStatement" || keyword === "ForOfStatement";
        }
 
        /**
         * Checks newlines around variable declarations.
         * @private
         * @param {ASTNode} node - `VariableDeclaration` node to test
         * @returns {void}
         */
        function checkForNewLine(node) {
            if (isForTypeSpecifier(node.parent.type)) {
                return;
            }
 
            const declarations = node.declarations;
            let prev;
 
            declarations.forEach(current => {
                if (prev && prev.loc.end.line === current.loc.start.line) {
                    if (always || prev.init || current.init) {
                        context.report({
                            node,
                            message: ERROR_MESSAGE,
                            loc: current.loc.start,
                            fix: fixer => fixer.insertTextBefore(current, "\n")
                        });
                    }
                }
                prev = current;
            });
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            VariableDeclaration: checkForNewLine
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/one-var.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/one-var.js

Statements: 8.18% (9 / 110)      Branches: 0% (0 / 109)      Functions: 0% (0 / 10)      Lines: 8.18% (9 / 110)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369                      1                                                                                                                                                                                                                               1                       1                   1                 1                         1                                     1                                     1                                       1                                                                                                                                                                                                                                                                                              
/**
 * @fileoverview A rule to control the use of single variable declarations.
 * @author Ian Christian Myers
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce variables to be declared either together or separately in functions",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                oneOf: [
                    {
                        enum: ["always", "never"]
                    },
                    {
                        type: "object",
                        properties: {
                            var: {
                                enum: ["always", "never"]
                            },
                            let: {
                                enum: ["always", "never"]
                            },
                            const: {
                                enum: ["always", "never"]
                            }
                        },
                        additionalProperties: false
                    },
                    {
                        type: "object",
                        properties: {
                            initialized: {
                                enum: ["always", "never"]
                            },
                            uninitialized: {
                                enum: ["always", "never"]
                            }
                        },
                        additionalProperties: false
                    }
                ]
            }
        ]
    },
 
    create(context) {
 
        const MODE_ALWAYS = "always",
            MODE_NEVER = "never";
 
        const mode = context.options[0] || MODE_ALWAYS;
 
        const options = {
        };
 
        if (typeof mode === "string") { // simple options configuration with just a string
            options.var = { uninitialized: mode, initialized: mode };
            options.let = { uninitialized: mode, initialized: mode };
            options.const = { uninitialized: mode, initialized: mode };
        } else if (typeof mode === "object") { // options configuration is an object
            if (mode.hasOwnProperty("var") && typeof mode.var === "string") {
                options.var = { uninitialized: mode.var, initialized: mode.var };
            }
            if (mode.hasOwnProperty("let") && typeof mode.let === "string") {
                options.let = { uninitialized: mode.let, initialized: mode.let };
            }
            if (mode.hasOwnProperty("const") && typeof mode.const === "string") {
                options.const = { uninitialized: mode.const, initialized: mode.const };
            }
            if (mode.hasOwnProperty("uninitialized")) {
                if (!options.var) {
                    options.var = {};
                }
                if (!options.let) {
                    options.let = {};
                }
                if (!options.const) {
                    options.const = {};
                }
                options.var.uninitialized = mode.uninitialized;
                options.let.uninitialized = mode.uninitialized;
                options.const.uninitialized = mode.uninitialized;
            }
            if (mode.hasOwnProperty("initialized")) {
                if (!options.var) {
                    options.var = {};
                }
                if (!options.let) {
                    options.let = {};
                }
                if (!options.const) {
                    options.const = {};
                }
                options.var.initialized = mode.initialized;
                options.let.initialized = mode.initialized;
                options.const.initialized = mode.initialized;
            }
        }
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        const functionStack = [];
        const blockStack = [];
 
        /**
         * Increments the blockStack counter.
         * @returns {void}
         * @private
         */
        function startBlock() {
            blockStack.push({
                let: { initialized: false, uninitialized: false },
                const: { initialized: false, uninitialized: false }
            });
        }
 
        /**
         * Increments the functionStack counter.
         * @returns {void}
         * @private
         */
        function startFunction() {
            functionStack.push({ initialized: false, uninitialized: false });
            startBlock();
        }
 
        /**
         * Decrements the blockStack counter.
         * @returns {void}
         * @private
         */
        function endBlock() {
            blockStack.pop();
        }
 
        /**
         * Decrements the functionStack counter.
         * @returns {void}
         * @private
         */
        function endFunction() {
            functionStack.pop();
            endBlock();
        }
 
        /**
         * Records whether initialized or uninitialized variables are defined in current scope.
         * @param {string} statementType node.kind, one of: "var", "let", or "const"
         * @param {ASTNode[]} declarations List of declarations
         * @param {Object} currentScope The scope being investigated
         * @returns {void}
         * @private
         */
        function recordTypes(statementType, declarations, currentScope) {
            for (let i = 0; i < declarations.length; i++) {
                if (declarations[i].init === null) {
                    if (options[statementType] && options[statementType].uninitialized === MODE_ALWAYS) {
                        currentScope.uninitialized = true;
                    }
                } else {
                    if (options[statementType] && options[statementType].initialized === MODE_ALWAYS) {
                        currentScope.initialized = true;
                    }
                }
            }
        }
 
        /**
         * Determines the current scope (function or block)
         * @param  {string} statementType node.kind, one of: "var", "let", or "const"
         * @returns {Object} The scope associated with statementType
         */
        function getCurrentScope(statementType) {
            let currentScope;
 
            if (statementType === "var") {
                currentScope = functionStack[functionStack.length - 1];
            } else if (statementType === "let") {
                currentScope = blockStack[blockStack.length - 1].let;
            } else if (statementType === "const") {
                currentScope = blockStack[blockStack.length - 1].const;
            }
            return currentScope;
        }
 
        /**
         * Counts the number of initialized and uninitialized declarations in a list of declarations
         * @param {ASTNode[]} declarations List of declarations
         * @returns {Object} Counts of 'uninitialized' and 'initialized' declarations
         * @private
         */
        function countDeclarations(declarations) {
            const counts = { uninitialized: 0, initialized: 0 };
 
            for (let i = 0; i < declarations.length; i++) {
                if (declarations[i].init === null) {
                    counts.uninitialized++;
                } else {
                    counts.initialized++;
                }
            }
            return counts;
        }
 
        /**
         * Determines if there is more than one var statement in the current scope.
         * @param {string} statementType node.kind, one of: "var", "let", or "const"
         * @param {ASTNode[]} declarations List of declarations
         * @returns {boolean} Returns true if it is the first var declaration, false if not.
         * @private
         */
        function hasOnlyOneStatement(statementType, declarations) {
 
            const declarationCounts = countDeclarations(declarations);
            const currentOptions = options[statementType] || {};
            const currentScope = getCurrentScope(statementType);
 
            if (currentOptions.uninitialized === MODE_ALWAYS && currentOptions.initialized === MODE_ALWAYS) {
                if (currentScope.uninitialized || currentScope.initialized) {
                    return false;
                }
            }
 
            if (declarationCounts.uninitialized > 0) {
                if (currentOptions.uninitialized === MODE_ALWAYS && currentScope.uninitialized) {
                    return false;
                }
            }
            if (declarationCounts.initialized > 0) {
                if (currentOptions.initialized === MODE_ALWAYS && currentScope.initialized) {
                    return false;
                }
            }
            recordTypes(statementType, declarations, currentScope);
            return true;
        }
 
 
        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------
 
        return {
            Program: startFunction,
            FunctionDeclaration: startFunction,
            FunctionExpression: startFunction,
            ArrowFunctionExpression: startFunction,
            BlockStatement: startBlock,
            ForStatement: startBlock,
            ForInStatement: startBlock,
            ForOfStatement: startBlock,
            SwitchStatement: startBlock,
 
            VariableDeclaration(node) {
                const parent = node.parent;
                const type = node.kind;
 
                if (!options[type]) {
                    return;
                }
 
                const declarations = node.declarations;
                const declarationCounts = countDeclarations(declarations);
 
                // always
                if (!hasOnlyOneStatement(type, declarations)) {
                    if (options[type].initialized === MODE_ALWAYS && options[type].uninitialized === MODE_ALWAYS) {
                        context.report({
                            node,
                            message: "Combine this with the previous '{{type}}' statement.",
                            data: {
                                type
                            }
                        });
                    } else {
                        if (options[type].initialized === MODE_ALWAYS) {
                            context.report({
                                node,
                                message: "Combine this with the previous '{{type}}' statement with initialized variables.",
                                data: {
                                    type
                                }
                            });
                        }
                        if (options[type].uninitialized === MODE_ALWAYS) {
                            if (node.parent.left === node && (node.parent.type === "ForInStatement" || node.parent.type === "ForOfStatement")) {
                                return;
                            }
                            context.report({
                                node,
                                message: "Combine this with the previous '{{type}}' statement with uninitialized variables.",
                                data: {
                                    type
                                }
                            });
                        }
                    }
                }
 
                // never
                if (parent.type !== "ForStatement" || parent.init !== node) {
                    const totalDeclarations = declarationCounts.uninitialized + declarationCounts.initialized;
 
                    if (totalDeclarations > 1) {
 
                        if (options[type].initialized === MODE_NEVER && options[type].uninitialized === MODE_NEVER) {
 
                            // both initialized and uninitialized
                            context.report({
                                node,
                                message: "Split '{{type}}' declarations into multiple statements.",
                                data: {
                                    type
                                }
                            });
                        } else if (options[type].initialized === MODE_NEVER && declarationCounts.initialized > 0) {
 
                            // initialized
                            context.report({
                                node,
                                message: "Split initialized '{{type}}' declarations into multiple statements.",
                                data: {
                                    type
                                }
                            });
                        } else if (options[type].uninitialized === MODE_NEVER && declarationCounts.uninitialized > 0) {
 
                            // uninitialized
                            context.report({
                                node,
                                message: "Split uninitialized '{{type}}' declarations into multiple statements.",
                                data: {
                                    type
                                }
                            });
                        }
                    }
                }
            },
 
            "ForStatement:exit": endBlock,
            "ForOfStatement:exit": endBlock,
            "ForInStatement:exit": endBlock,
            "SwitchStatement:exit": endBlock,
            "BlockStatement:exit": endBlock,
            "Program:exit": endFunction,
            "FunctionDeclaration:exit": endFunction,
            "FunctionExpression:exit": endFunction,
            "ArrowFunctionExpression:exit": endFunction
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/operator-assignment.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/operator-assignment.js

Statements: 17.31% (9 / 52)      Branches: 0% (0 / 39)      Functions: 0% (0 / 10)      Lines: 17.65% (9 / 51)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208                    1                         1                     1                                   1                                                               1         1                                                   1                 1                                                                                           1                                                                          
/**
 * @fileoverview Rule to replace assignment expressions with operator assignment
 * @author Brandon Mills
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks whether an operator is commutative and has an operator assignment
 * shorthand form.
 * @param   {string}  operator Operator to check.
 * @returns {boolean}          True if the operator is commutative and has a
 *     shorthand form.
 */
function isCommutativeOperatorWithShorthand(operator) {
    return ["*", "&", "^", "|"].indexOf(operator) >= 0;
}
 
/**
 * Checks whether an operator is not commuatative and has an operator assignment
 * shorthand form.
 * @param   {string}  operator Operator to check.
 * @returns {boolean}          True if the operator is not commuatative and has
 *     a shorthand form.
 */
function isNonCommutativeOperatorWithShorthand(operator) {
    return ["+", "-", "/", "%", "<<", ">>", ">>>", "**"].indexOf(operator) >= 0;
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
/**
 * Checks whether two expressions reference the same value. For example:
 *     a = a
 *     a.b = a.b
 *     a[0] = a[0]
 *     a['b'] = a['b']
 * @param   {ASTNode} a Left side of the comparison.
 * @param   {ASTNode} b Right side of the comparison.
 * @returns {boolean}   True if both sides match and reference the same value.
 */
function same(a, b) {
    if (a.type !== b.type) {
        return false;
    }
 
    switch (a.type) {
        case "Identifier":
            return a.name === b.name;
 
        case "Literal":
            return a.value === b.value;
 
        case "MemberExpression":
 
            /*
             * x[0] = x[0]
             * x[y] = x[y]
             * x.y = x.y
             */
            return same(a.object, b.object) && same(a.property, b.property);
 
        default:
            return false;
    }
}
 
/**
* Determines if the left side of a node can be safely fixed (i.e. if it activates the same getters/setters and)
* toString calls regardless of whether assignment shorthand is used)
* @param {ASTNode} node The node on the left side of the expression
* @returns {boolean} `true` if the node can be fixed
*/
function canBeFixed(node) {
    return node.type === "Identifier" ||
        node.type === "MemberExpression" && node.object.type === "Identifier" && (!node.computed || node.property.type === "Literal");
}
 
module.exports = {
    meta: {
        docs: {
            description: "require or disallow assignment operator shorthand where possible",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                enum: ["always", "never"]
            }
        ],
 
        fixable: "code"
    },
 
    create(context) {
 
        const sourceCode = context.getSourceCode();
 
        /**
        * Returns the operator token of an AssignmentExpression or BinaryExpression
        * @param {ASTNode} node An AssignmentExpression or BinaryExpression node
        * @returns {Token} The operator token in the node
        */
        function getOperatorToken(node) {
            return sourceCode.getFirstTokenBetween(node.left, node.right, token => token.value === node.operator);
        }
 
        /**
         * Ensures that an assignment uses the shorthand form where possible.
         * @param   {ASTNode} node An AssignmentExpression node.
         * @returns {void}
         */
        function verify(node) {
            if (node.operator !== "=" || node.right.type !== "BinaryExpression") {
                return;
            }
 
            const left = node.left;
            const expr = node.right;
            const operator = expr.operator;
 
            if (isCommutativeOperatorWithShorthand(operator) || isNonCommutativeOperatorWithShorthand(operator)) {
                if (same(left, expr.left)) {
                    context.report({
                        node,
                        message: "Assignment can be replaced with operator assignment.",
                        fix(fixer) {
                            if (canBeFixed(left)) {
                                const equalsToken = getOperatorToken(node);
                                const operatorToken = getOperatorToken(expr);
                                const leftText = sourceCode.getText().slice(node.range[0], equalsToken.range[0]);
                                const rightText = sourceCode.getText().slice(operatorToken.range[1], node.right.range[1]);
 
                                return fixer.replaceText(node, `${leftText}${expr.operator}=${rightText}`);
                            }
                            return null;
                        }
                    });
                } else if (same(left, expr.right) && isCommutativeOperatorWithShorthand(operator)) {
 
                    /*
                     * This case can't be fixed safely.
                     * If `a` and `b` both have custom valueOf() behavior, then fixing `a = b * a` to `a *= b` would
                     * change the execution order of the valueOf() functions.
                     */
                    context.report({
                        node,
                        message: "Assignment can be replaced with operator assignment."
                    });
                }
            }
        }
 
        /**
         * Warns if an assignment expression uses operator assignment shorthand.
         * @param   {ASTNode} node An AssignmentExpression node.
         * @returns {void}
         */
        function prohibit(node) {
            if (node.operator !== "=") {
                context.report({
                    node,
                    message: "Unexpected operator assignment shorthand.",
                    fix(fixer) {
                        if (canBeFixed(node.left)) {
                            const operatorToken = getOperatorToken(node);
                            const leftText = sourceCode.getText().slice(node.range[0], operatorToken.range[0]);
                            const newOperator = node.operator.slice(0, -1);
                            let rightText;
 
                            // If this change would modify precedence (e.g. `foo *= bar + 1` => `foo = foo * (bar + 1)`), parenthesize the right side.
                            if (
                                astUtils.getPrecedence(node.right) <= astUtils.getPrecedence({ type: "BinaryExpression", operator: newOperator }) &&
                                !astUtils.isParenthesised(sourceCode, node.right)
                            ) {
                                rightText = `${sourceCode.text.slice(operatorToken.range[1], node.right.range[0])}(${sourceCode.getText(node.right)})`;
                            } else {
                                rightText = sourceCode.text.slice(operatorToken.range[1], node.range[1]);
                            }
 
                            return fixer.replaceText(node, `${leftText}= ${leftText}${newOperator}${rightText}`);
                        }
                        return null;
                    }
                });
            }
        }
 
        return {
            AssignmentExpression: context.options[0] !== "never" ? verify : prohibit
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/operator-linebreak.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/operator-linebreak.js

Statements: 8.77% (5 / 57)      Branches: 0% (0 / 63)      Functions: 0% (0 / 6)      Lines: 8.77% (5 / 57)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250                      1           1                                                                                                                     1                                                                                                                 1                                                                                                                                                                                     1                                                  
/**
 * @fileoverview Operator linebreak - enforces operator linebreak style of two types: after and before
 * @author Benoît Zugmeyer
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent linebreak style for operators",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                enum: ["after", "before", "none", null]
            },
            {
                type: "object",
                properties: {
                    overrides: {
                        type: "object",
                        properties: {
                            anyOf: {
                                type: "string",
                                enum: ["after", "before", "none", "ignore"]
                            }
                        }
                    }
                },
                additionalProperties: false
            }
        ],
 
        fixable: "code"
    },
 
    create(context) {
 
        const usedDefaultGlobal = !context.options[0];
        const globalStyle = context.options[0] || "after";
        const options = context.options[1] || {};
        const styleOverrides = options.overrides ? Object.assign({}, options.overrides) : {};
 
        if (usedDefaultGlobal && !styleOverrides["?"]) {
            styleOverrides["?"] = "before";
        }
 
        if (usedDefaultGlobal && !styleOverrides[":"]) {
            styleOverrides[":"] = "before";
        }
 
        const sourceCode = context.getSourceCode();
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
        * Gets a fixer function to fix rule issues
        * @param {Token} operatorToken The operator token of an expression
        * @param {string} desiredStyle The style for the rule. One of 'before', 'after', 'none'
        * @returns {Function} A fixer function
        */
        function getFixer(operatorToken, desiredStyle) {
            return fixer => {
                const tokenBefore = sourceCode.getTokenBefore(operatorToken);
                const tokenAfter = sourceCode.getTokenAfter(operatorToken);
                const textBefore = sourceCode.text.slice(tokenBefore.range[1], operatorToken.range[0]);
                const textAfter = sourceCode.text.slice(operatorToken.range[1], tokenAfter.range[0]);
                const hasLinebreakBefore = !astUtils.isTokenOnSameLine(tokenBefore, operatorToken);
                const hasLinebreakAfter = !astUtils.isTokenOnSameLine(operatorToken, tokenAfter);
                let newTextBefore, newTextAfter;
 
                if (hasLinebreakBefore !== hasLinebreakAfter && desiredStyle !== "none") {
 
                    // If there is a comment before and after the operator, don't do a fix.
                    if (sourceCode.getTokenBefore(operatorToken, { includeComments: true }) !== tokenBefore && sourceCode.getTokenAfter(operatorToken, { includeComments: true }) !== tokenAfter) {
                        return null;
                    }
 
                    /*
                     * If there is only one linebreak and it's on the wrong side of the operator, swap the text before and after the operator.
                     * foo &&
                     *           bar
                     * would get fixed to
                     * foo
                     *        && bar
                     */
                    newTextBefore = textAfter;
                    newTextAfter = textBefore;
                } else {
                    const LINEBREAK_REGEX = astUtils.createGlobalLinebreakMatcher();
 
                    // Otherwise, if no linebreak is desired and no comments interfere, replace the linebreaks with empty strings.
                    newTextBefore = desiredStyle === "before" || textBefore.trim() ? textBefore : textBefore.replace(LINEBREAK_REGEX, "");
                    newTextAfter = desiredStyle === "after" || textAfter.trim() ? textAfter : textAfter.replace(LINEBREAK_REGEX, "");
 
                    // If there was no change (due to interfering comments), don't output a fix.
                    if (newTextBefore === textBefore && newTextAfter === textAfter) {
                        return null;
                    }
                }
 
                if (newTextAfter === "" && tokenAfter.type === "Punctuator" && "+-".includes(operatorToken.value) && tokenAfter.value === operatorToken.value) {
 
                    // To avoid accidentally creating a ++ or -- operator, insert a space if the operator is a +/- and the following token is a unary +/-.
                    newTextAfter += " ";
                }
 
                return fixer.replaceTextRange([tokenBefore.range[1], tokenAfter.range[0]], newTextBefore + operatorToken.value + newTextAfter);
            };
        }
 
        /**
         * Checks the operator placement
         * @param {ASTNode} node The node to check
         * @param {ASTNode} leftSide The node that comes before the operator in `node`
         * @private
         * @returns {void}
         */
        function validateNode(node, leftSide) {
 
            // When the left part of a binary expression is a single expression wrapped in
            // parentheses (ex: `(a) + b`), leftToken will be the last token of the expression
            // and operatorToken will be the closing parenthesis.
            // The leftToken should be the last closing parenthesis, and the operatorToken
            // should be the token right after that.
            const operatorToken = sourceCode.getTokenAfter(leftSide, astUtils.isNotClosingParenToken);
            const leftToken = sourceCode.getTokenBefore(operatorToken);
            const rightToken = sourceCode.getTokenAfter(operatorToken);
            const operator = operatorToken.value;
            const operatorStyleOverride = styleOverrides[operator];
            const style = operatorStyleOverride || globalStyle;
            const fix = getFixer(operatorToken, style);
 
            // if single line
            if (astUtils.isTokenOnSameLine(leftToken, operatorToken) &&
                    astUtils.isTokenOnSameLine(operatorToken, rightToken)) {
 
                // do nothing.
 
            } else if (operatorStyleOverride !== "ignore" && !astUtils.isTokenOnSameLine(leftToken, operatorToken) &&
                    !astUtils.isTokenOnSameLine(operatorToken, rightToken)) {
 
                // lone operator
                context.report({
                    node,
                    loc: {
                        line: operatorToken.loc.end.line,
                        column: operatorToken.loc.end.column
                    },
                    message: "Bad line breaking before and after '{{operator}}'.",
                    data: {
                        operator
                    },
                    fix
                });
 
            } else if (style === "before" && astUtils.isTokenOnSameLine(leftToken, operatorToken)) {
 
                context.report({
                    node,
                    loc: {
                        line: operatorToken.loc.end.line,
                        column: operatorToken.loc.end.column
                    },
                    message: "'{{operator}}' should be placed at the beginning of the line.",
                    data: {
                        operator
                    },
                    fix
                });
 
            } else if (style === "after" && astUtils.isTokenOnSameLine(operatorToken, rightToken)) {
 
                context.report({
                    node,
                    loc: {
                        line: operatorToken.loc.end.line,
                        column: operatorToken.loc.end.column
                    },
                    message: "'{{operator}}' should be placed at the end of the line.",
                    data: {
                        operator
                    },
                    fix
                });
 
            } else if (style === "none") {
 
                context.report({
                    node,
                    loc: {
                        line: operatorToken.loc.end.line,
                        column: operatorToken.loc.end.column
                    },
                    message: "There should be no line break before or after '{{operator}}'.",
                    data: {
                        operator
                    },
                    fix
                });
 
            }
        }
 
        /**
         * Validates a binary expression using `validateNode`
         * @param {BinaryExpression|LogicalExpression|AssignmentExpression} node node to be validated
         * @returns {void}
         */
        function validateBinaryExpression(node) {
            validateNode(node, node.left);
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            BinaryExpression: validateBinaryExpression,
            LogicalExpression: validateBinaryExpression,
            AssignmentExpression: validateBinaryExpression,
            VariableDeclarator(node) {
                if (node.init) {
                    validateNode(node, node.id);
                }
            },
            ConditionalExpression(node) {
                validateNode(node, node.test);
                validateNode(node, node.consequent);
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/padded-blocks.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/padded-blocks.js

Statements: 12.68% (9 / 71)      Branches: 2.27% (1 / 44)      Functions: 0% (0 / 15)      Lines: 12.68% (9 / 71)      Ignored: 1 statement, 1 branch     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254                      1                                                                                                                                 1                       1                   1                   1                                 1                                 1                     1                 1                                                                                                                                                                                      
/**
 * @fileoverview A rule to ensure blank lines within blocks.
 * @author Mathias Schreck <https://github.com/lo1tuma>
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require or disallow padding within blocks",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                oneOf: [
                    {
                        enum: ["always", "never"]
                    },
                    {
                        type: "object",
                        properties: {
                            blocks: {
                                enum: ["always", "never"]
                            },
                            switches: {
                                enum: ["always", "never"]
                            },
                            classes: {
                                enum: ["always", "never"]
                            }
                        },
                        additionalProperties: false,
                        minProperties: 1
                    }
                ]
            }
        ]
    },
 
    create(context) {
        const options = {};
        const config = context.options[0] || "always";
 
        if (typeof config === "string") {
            options.blocks = config === "always";
        } else {
            if (config.hasOwnProperty("blocks")) {
                options.blocks = config.blocks === "always";
            }
            if (config.hasOwnProperty("switches")) {
                options.switches = config.switches === "always";
            }
            if (config.hasOwnProperty("classes")) {
                options.classes = config.classes === "always";
            }
        }
 
        const ALWAYS_MESSAGE = "Block must be padded by blank lines.",
            NEVER_MESSAGE = "Block must not be padded by blank lines.";
 
        const sourceCode = context.getSourceCode();
 
        /**
         * Gets the open brace token from a given node.
         * @param {ASTNode} node - A BlockStatement or SwitchStatement node from which to get the open brace.
         * @returns {Token} The token of the open brace.
         */
        function getOpenBrace(node) {
            if (node.type === "SwitchStatement") {
                return sourceCode.getTokenBefore(node.cases[0]);
            }
            return sourceCode.getFirstToken(node);
        }
 
        /**
         * Checks if the given parameter is a comment node
         * @param {ASTNode|Token} node An AST node or token
         * @returns {boolean} True if node is a comment
         */
        function isComment(node) {
            return node.type === "Line" || node.type === "Block";
        }
 
        /**
         * Checks if there is padding between two tokens
         * @param {Token} first The first token
         * @param {Token} second The second token
         * @returns {boolean} True if there is at least a line between the tokens
         */
        function isPaddingBetweenTokens(first, second) {
            return second.loc.start.line - first.loc.end.line >= 2;
        }
 
 
        /**
         * Checks if the given token has a blank line after it.
         * @param {Token} token The token to check.
         * @returns {boolean} Whether or not the token is followed by a blank line.
         */
        function getFirstBlockToken(token) {
            let prev = token,
                first = token;
 
            do {
                prev = first;
                first = sourceCode.getTokenAfter(first, { includeComments: true });
            } while (isComment(first) && first.loc.start.line === prev.loc.end.line);
 
            return first;
        }
 
        /**
         * Checks if the given token is preceeded by a blank line.
         * @param {Token} token The token to check
         * @returns {boolean} Whether or not the token is preceeded by a blank line
         */
        function getLastBlockToken(token) {
            let last = token,
                next = token;
 
            do {
                next = last;
                last = sourceCode.getTokenBefore(last, { includeComments: true });
            } while (isComment(last) && last.loc.end.line === next.loc.start.line);
 
            return last;
        }
 
        /**
         * Checks if a node should be padded, according to the rule config.
         * @param {ASTNode} node The AST node to check.
         * @returns {boolean} True if the node should be padded, false otherwise.
         */
        function requirePaddingFor(node) {
            switch (node.type) {
                case "BlockStatement":
                    return options.blocks;
                case "SwitchStatement":
                    return options.switches;
                case "ClassBody":
                    return options.classes;
 
                /* istanbul ignore next */
                default:
                    throw new Error("unreachable");
            }
        }
 
        /**
         * Checks the given BlockStatement node to be padded if the block is not empty.
         * @param {ASTNode} node The AST node of a BlockStatement.
         * @returns {void} undefined.
         */
        function checkPadding(node) {
            const openBrace = getOpenBrace(node),
                firstBlockToken = getFirstBlockToken(openBrace),
                tokenBeforeFirst = sourceCode.getTokenBefore(firstBlockToken, { includeComments: true }),
                closeBrace = sourceCode.getLastToken(node),
                lastBlockToken = getLastBlockToken(closeBrace),
                tokenAfterLast = sourceCode.getTokenAfter(lastBlockToken, { includeComments: true }),
                blockHasTopPadding = isPaddingBetweenTokens(tokenBeforeFirst, firstBlockToken),
                blockHasBottomPadding = isPaddingBetweenTokens(lastBlockToken, tokenAfterLast);
 
            if (requirePaddingFor(node)) {
                if (!blockHasTopPadding) {
                    context.report({
                        node,
                        loc: { line: tokenBeforeFirst.loc.start.line, column: tokenBeforeFirst.loc.start.column },
                        fix(fixer) {
                            return fixer.insertTextAfter(tokenBeforeFirst, "\n");
                        },
                        message: ALWAYS_MESSAGE
                    });
                }
                if (!blockHasBottomPadding) {
                    context.report({
                        node,
                        loc: { line: tokenAfterLast.loc.end.line, column: tokenAfterLast.loc.end.column - 1 },
                        fix(fixer) {
                            return fixer.insertTextBefore(tokenAfterLast, "\n");
                        },
                        message: ALWAYS_MESSAGE
                    });
                }
            } else {
                if (blockHasTopPadding) {
 
                    context.report({
                        node,
                        loc: { line: tokenBeforeFirst.loc.start.line, column: tokenBeforeFirst.loc.start.column },
                        fix(fixer) {
                            return fixer.replaceTextRange([tokenBeforeFirst.end, firstBlockToken.start - firstBlockToken.loc.start.column], "\n");
                        },
                        message: NEVER_MESSAGE
                    });
                }
 
                if (blockHasBottomPadding) {
 
                    context.report({
                        node,
                        loc: { line: tokenAfterLast.loc.end.line, column: tokenAfterLast.loc.end.column - 1 },
                        message: NEVER_MESSAGE,
                        fix(fixer) {
                            return fixer.replaceTextRange([lastBlockToken.end, tokenAfterLast.start - tokenAfterLast.loc.start.column], "\n");
                        }
                    });
                }
            }
        }
 
        const rule = {};
 
        if (options.hasOwnProperty("switches")) {
            rule.SwitchStatement = function(node) {
                if (node.cases.length === 0) {
                    return;
                }
                checkPadding(node);
            };
        }
 
        if (options.hasOwnProperty("blocks")) {
            rule.BlockStatement = function(node) {
                if (node.body.length === 0) {
                    return;
                }
                checkPadding(node);
            };
        }
 
        if (options.hasOwnProperty("classes")) {
            rule.ClassBody = function(node) {
                if (node.body.length === 0) {
                    return;
                }
                checkPadding(node);
            };
        }
 
        return rule;
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/prefer-arrow-callback.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/prefer-arrow-callback.js

Statements: 12.82% (10 / 78)      Branches: 0% (0 / 72)      Functions: 0% (0 / 14)      Lines: 13.16% (10 / 76)      Ignored: 2 statements     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297                                1                     1                 1                                   1                   1                                                                                                   1                   1               1                                                                                         1               1                                                                                                                                                                                                                              
/**
 * @fileoverview A rule to suggest using arrow functions as callbacks.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks whether or not a given variable is a function name.
 * @param {escope.Variable} variable - A variable to check.
 * @returns {boolean} `true` if the variable is a function name.
 */
function isFunctionName(variable) {
    return variable && variable.defs[0].type === "FunctionName";
}
 
/**
 * Checks whether or not a given MetaProperty node equals to a given value.
 * @param {ASTNode} node - A MetaProperty node to check.
 * @param {string} metaName - The name of `MetaProperty.meta`.
 * @param {string} propertyName - The name of `MetaProperty.property`.
 * @returns {boolean} `true` if the node is the specific value.
 */
function checkMetaProperty(node, metaName, propertyName) {
    return node.meta.name === metaName && node.property.name === propertyName;
}
 
/**
 * Gets the variable object of `arguments` which is defined implicitly.
 * @param {escope.Scope} scope - A scope to get.
 * @returns {escope.Variable} The found variable object.
 */
function getVariableOfArguments(scope) {
    const variables = scope.variables;
 
    for (let i = 0; i < variables.length; ++i) {
        const variable = variables[i];
 
        if (variable.name === "arguments") {
 
            /*
             * If there was a parameter which is named "arguments", the
             * implicit "arguments" is not defined.
             * So does fast return with null.
             */
            return (variable.identifiers.length === 0) ? variable : null;
        }
    }
 
    /* istanbul ignore next */
    return null;
}
 
/**
 * Checkes whether or not a given node is a callback.
 * @param {ASTNode} node - A node to check.
 * @returns {Object}
 *   {boolean} retv.isCallback - `true` if the node is a callback.
 *   {boolean} retv.isLexicalThis - `true` if the node is with `.bind(this)`.
 */
function getCallbackInfo(node) {
    const retv = { isCallback: false, isLexicalThis: false };
    let parent = node.parent;
 
    while (node) {
        switch (parent.type) {
 
            // Checks parents recursively.
 
            case "LogicalExpression":
            case "ConditionalExpression":
                break;
 
            // Checks whether the parent node is `.bind(this)` call.
            case "MemberExpression":
                if (parent.object === node &&
                    !parent.property.computed &&
                    parent.property.type === "Identifier" &&
                    parent.property.name === "bind" &&
                    parent.parent.type === "CallExpression" &&
                    parent.parent.callee === parent
                ) {
                    retv.isLexicalThis = (
                        parent.parent.arguments.length === 1 &&
                        parent.parent.arguments[0].type === "ThisExpression"
                    );
                    node = parent;
                    parent = parent.parent;
                } else {
                    return retv;
                }
                break;
 
            // Checks whether the node is a callback.
            case "CallExpression":
            case "NewExpression":
                if (parent.callee !== node) {
                    retv.isCallback = true;
                }
                return retv;
 
            default:
                return retv;
        }
 
        node = parent;
        parent = parent.parent;
    }
 
    /* istanbul ignore next */
    throw new Error("unreachable");
}
 
/**
* Checks whether a simple list of parameters contains any duplicates. This does not handle complex
parameter lists (e.g. with destructuring), since complex parameter lists are a SyntaxError with duplicate
parameter names anyway. Instead, it always returns `false` for complex parameter lists.
* @param {ASTNode[]} paramsList The list of parameters for a function
* @returns {boolean} `true` if the list of parameters contains any duplicates
*/
function hasDuplicateParams(paramsList) {
    return paramsList.every(param => param.type === "Identifier") && paramsList.length !== new Set(paramsList.map(param => param.name)).size;
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require arrow functions as callbacks",
            category: "ECMAScript 6",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    allowNamedFunctions: {
                        type: "boolean"
                    },
                    allowUnboundThis: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ],
 
        fixable: "code"
    },
 
    create(context) {
        const options = context.options[0] || {};
 
        const allowUnboundThis = options.allowUnboundThis !== false;  // default to true
        const allowNamedFunctions = options.allowNamedFunctions;
        const sourceCode = context.getSourceCode();
 
        /*
         * {Array<{this: boolean, super: boolean, meta: boolean}>}
         * - this - A flag which shows there are one or more ThisExpression.
         * - super - A flag which shows there are one or more Super.
         * - meta - A flag which shows there are one or more MethProperty.
         */
        let stack = [];
 
        /**
         * Pushes new function scope with all `false` flags.
         * @returns {void}
         */
        function enterScope() {
            stack.push({ this: false, super: false, meta: false });
        }
 
        /**
         * Pops a function scope from the stack.
         * @returns {{this: boolean, super: boolean, meta: boolean}} The information of the last scope.
         */
        function exitScope() {
            return stack.pop();
        }
 
        return {
 
            // Reset internal state.
            Program() {
                stack = [];
            },
 
            // If there are below, it cannot replace with arrow functions merely.
            ThisExpression() {
                const info = stack[stack.length - 1];
 
                if (info) {
                    info.this = true;
                }
            },
 
            Super() {
                const info = stack[stack.length - 1];
 
                if (info) {
                    info.super = true;
                }
            },
 
            MetaProperty(node) {
                const info = stack[stack.length - 1];
 
                if (info && checkMetaProperty(node, "new", "target")) {
                    info.meta = true;
                }
            },
 
            // To skip nested scopes.
            FunctionDeclaration: enterScope,
            "FunctionDeclaration:exit": exitScope,
 
            // Main.
            FunctionExpression: enterScope,
            "FunctionExpression:exit"(node) {
                const scopeInfo = exitScope();
 
                // Skip named function expressions
                if (allowNamedFunctions && node.id && node.id.name) {
                    return;
                }
 
                // Skip generators.
                if (node.generator) {
                    return;
                }
 
                // Skip recursive functions.
                const nameVar = context.getDeclaredVariables(node)[0];
 
                if (isFunctionName(nameVar) && nameVar.references.length > 0) {
                    return;
                }
 
                // Skip if it's using arguments.
                const variable = getVariableOfArguments(context.getScope());
 
                if (variable && variable.references.length > 0) {
                    return;
                }
 
                // Reports if it's a callback which can replace with arrows.
                const callbackInfo = getCallbackInfo(node);
 
                if (callbackInfo.isCallback &&
                    (!allowUnboundThis || !scopeInfo.this || callbackInfo.isLexicalThis) &&
                    !scopeInfo.super &&
                    !scopeInfo.meta
                ) {
                    context.report({
                        node,
                        message: "Unexpected function expression.",
                        fix(fixer) {
                            if ((!callbackInfo.isLexicalThis && scopeInfo.this) || hasDuplicateParams(node.params)) {
 
                                // If the callback function does not have .bind(this) and contains a reference to `this`, there
                                // is no way to determine what `this` should be, so don't perform any fixes.
                                // If the callback function has duplicates in its list of parameters (possible in sloppy mode),
                                // don't replace it with an arrow function, because this is a SyntaxError with arrow functions.
                                return null;
                            }
 
                            const paramsLeftParen = node.params.length ? sourceCode.getTokenBefore(node.params[0]) : sourceCode.getTokenBefore(node.body, 1);
                            const paramsRightParen = sourceCode.getTokenBefore(node.body);
                            const asyncKeyword = node.async ? "async " : "";
                            const paramsFullText = sourceCode.text.slice(paramsLeftParen.range[0], paramsRightParen.range[1]);
 
                            if (callbackInfo.isLexicalThis) {
 
                                // If the callback function has `.bind(this)`, replace it with an arrow function and remove the binding.
                                return fixer.replaceText(node.parent.parent, `${asyncKeyword}${paramsFullText} => ${sourceCode.getText(node.body)}`);
                            }
 
                            // Otherwise, only replace the `function` keyword and parameters with the arrow function parameters.
                            return fixer.replaceTextRange([node.start, node.body.start], `${asyncKeyword}${paramsFullText} => `);
                        }
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/prefer-const.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/prefer-const.js

Statements: 13.48% (12 / 89)      Branches: 0% (0 / 66)      Functions: 0% (0 / 10)      Lines: 13.64% (12 / 88)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326                      1 1 1                 1               1                   1                                                                                   1                                                                                                                                           1                                                     1                                                                                       1                           1                                                                                     1                                                                                          
/**
 * @fileoverview A rule to suggest using of const declaration for variables that are never reassigned after declared.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const PATTERN_TYPE = /^(?:.+?Pattern|RestElement|SpreadProperty|ExperimentalRestProperty|Property)$/;
const DECLARATION_HOST_TYPE = /^(?:Program|BlockStatement|SwitchCase)$/;
const DESTRUCTURING_HOST_TYPE = /^(?:VariableDeclarator|AssignmentExpression)$/;
 
/**
 * Adds multiple items to the tail of an array.
 *
 * @param {any[]} array - A destination to add.
 * @param {any[]} values - Items to be added.
 * @returns {void}
 */
const pushAll = Function.apply.bind(Array.prototype.push);
 
/**
 * Checks whether a given node is located at `ForStatement.init` or not.
 *
 * @param {ASTNode} node - A node to check.
 * @returns {boolean} `true` if the node is located at `ForStatement.init`.
 */
function isInitOfForStatement(node) {
    return node.parent.type === "ForStatement" && node.parent.init === node;
}
 
/**
 * Checks whether a given Identifier node becomes a VariableDeclaration or not.
 *
 * @param {ASTNode} identifier - An Identifier node to check.
 * @returns {boolean} `true` if the node can become a VariableDeclaration.
 */
function canBecomeVariableDeclaration(identifier) {
    let node = identifier.parent;
 
    while (PATTERN_TYPE.test(node.type)) {
        node = node.parent;
    }
 
    return (
        node.type === "VariableDeclarator" ||
        (
            node.type === "AssignmentExpression" &&
            node.parent.type === "ExpressionStatement" &&
            DECLARATION_HOST_TYPE.test(node.parent.parent.type)
        )
    );
}
 
/**
 * Gets an identifier node of a given variable.
 *
 * If the initialization exists or one or more reading references exist before
 * the first assignment, the identifier node is the node of the declaration.
 * Otherwise, the identifier node is the node of the first assignment.
 *
 * If the variable should not change to const, this function returns null.
 * - If the variable is reassigned.
 * - If the variable is never initialized nor assigned.
 * - If the variable is initialized in a different scope from the declaration.
 * - If the unique assignment of the variable cannot change to a declaration.
 *   e.g. `if (a) b = 1` / `return (b = 1)`
 * - If the variable is declared in the global scope and `eslintUsed` is `true`.
 *   `/*exported foo` directive comment makes such variables. This rule does not
 *   warn such variables because this rule cannot distinguish whether the
 *   exported variables are reassigned or not.
 *
 * @param {escope.Variable} variable - A variable to get.
 * @param {boolean} ignoreReadBeforeAssign -
 *      The value of `ignoreReadBeforeAssign` option.
 * @returns {ASTNode|null}
 *      An Identifier node if the variable should change to const.
 *      Otherwise, null.
 */
function getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign) {
    if (variable.eslintUsed && variable.scope.type === "global") {
        return null;
    }
 
    /*
     * Due to a bug in acorn, code such as `let foo = 1; let foo = 2;` will not throw a syntax error. As a sanity
     * check, make sure that the variable only has one declaration. After the parsing bug is fixed, this check
     * will no longer be necessary, because variables declared with `let` or `const` should always have exactly one
     * declaration.
     * https://github.com/ternjs/acorn/issues/487
     */
    if (variable.defs.length > 1) {
        return null;
    }
 
    // Finds the unique WriteReference.
    let writer = null;
    let isReadBeforeInit = false;
    const references = variable.references;
 
    for (let i = 0; i < references.length; ++i) {
        const reference = references[i];
 
        if (reference.isWrite()) {
            const isReassigned = (
                writer !== null &&
                writer.identifier !== reference.identifier
            );
 
            if (isReassigned) {
                return null;
            }
            writer = reference;
 
        } else if (reference.isRead() && writer === null) {
            if (ignoreReadBeforeAssign) {
                return null;
            }
            isReadBeforeInit = true;
        }
    }
 
    // If the assignment is from a different scope, ignore it.
    // If the assignment cannot change to a declaration, ignore it.
    const shouldBeConst = (
        writer !== null &&
        writer.from === variable.scope &&
        canBecomeVariableDeclaration(writer.identifier)
    );
 
    if (!shouldBeConst) {
        return null;
    }
    if (isReadBeforeInit) {
        return variable.defs[0].name;
    }
    return writer.identifier;
}
 
/**
 * Gets the VariableDeclarator/AssignmentExpression node that a given reference
 * belongs to.
 * This is used to detect a mix of reassigned and never reassigned in a
 * destructuring.
 *
 * @param {escope.Reference} reference - A reference to get.
 * @returns {ASTNode|null} A VariableDeclarator/AssignmentExpression node or
 *      null.
 */
function getDestructuringHost(reference) {
    if (!reference.isWrite()) {
        return null;
    }
    let node = reference.identifier.parent;
 
    while (PATTERN_TYPE.test(node.type)) {
        node = node.parent;
    }
 
    if (!DESTRUCTURING_HOST_TYPE.test(node.type)) {
        return null;
    }
    return node;
}
 
/**
 * Groups by the VariableDeclarator/AssignmentExpression node that each
 * reference of given variables belongs to.
 * This is used to detect a mix of reassigned and never reassigned in a
 * destructuring.
 *
 * @param {escope.Variable[]} variables - Variables to group by destructuring.
 * @param {boolean} ignoreReadBeforeAssign -
 *      The value of `ignoreReadBeforeAssign` option.
 * @returns {Map<ASTNode, ASTNode[]>} Grouped identifier nodes.
 */
function groupByDestructuring(variables, ignoreReadBeforeAssign) {
    const identifierMap = new Map();
 
    for (let i = 0; i < variables.length; ++i) {
        const variable = variables[i];
        const references = variable.references;
        const identifier = getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign);
        let prevId = null;
 
        for (let j = 0; j < references.length; ++j) {
            const reference = references[j];
            const id = reference.identifier;
 
            // Avoid counting a reference twice or more for default values of
            // destructuring.
            if (id === prevId) {
                continue;
            }
            prevId = id;
 
            // Add the identifier node into the destructuring group.
            const group = getDestructuringHost(reference);
 
            if (group) {
                if (identifierMap.has(group)) {
                    identifierMap.get(group).push(identifier);
                } else {
                    identifierMap.set(group, [identifier]);
                }
            }
        }
    }
 
    return identifierMap;
}
 
/**
 * Finds the nearest parent of node with a given type.
 *
 * @param {ASTNode} node – The node to search from.
 * @param {string} type – The type field of the parent node.
 * @param {Function} shouldStop – a predicate that returns true if the traversal should stop, and false otherwise.
 * @returns {ASTNode} The closest ancestor with the specified type; null if no such ancestor exists.
 */
function findUp(node, type, shouldStop) {
    if (!node || shouldStop(node)) {
        return null;
    }
    if (node.type === type) {
        return node;
    }
    return findUp(node.parent, type, shouldStop);
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require `const` declarations for variables that are never reassigned after declared",
            category: "ECMAScript 6",
            recommended: false
        },
 
        fixable: "code",
 
        schema: [
            {
                type: "object",
                properties: {
                    destructuring: { enum: ["any", "all"] },
                    ignoreReadBeforeAssign: { type: "boolean" }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const options = context.options[0] || {};
        const sourceCode = context.getSourceCode();
        const checkingMixedDestructuring = options.destructuring !== "all";
        const ignoreReadBeforeAssign = options.ignoreReadBeforeAssign === true;
        const variables = [];
 
        /**
         * Reports given identifier nodes if all of the nodes should be declared
         * as const.
         *
         * The argument 'nodes' is an array of Identifier nodes.
         * This node is the result of 'getIdentifierIfShouldBeConst()', so it's
         * nullable. In simple declaration or assignment cases, the length of
         * the array is 1. In destructuring cases, the length of the array can
         * be 2 or more.
         *
         * @param {(escope.Reference|null)[]} nodes -
         *      References which are grouped by destructuring to report.
         * @returns {void}
         */
        function checkGroup(nodes) {
            const nodesToReport = nodes.filter(Boolean);
 
            if (nodes.length && (checkingMixedDestructuring || nodesToReport.length === nodes.length)) {
                const varDeclParent = findUp(nodes[0], "VariableDeclaration", parentNode => parentNode.type.endsWith("Statement"));
                const shouldFix = varDeclParent &&
 
                    // If there are multiple variable declarations, like {let a = 1, b = 2}, then
                    // do not attempt to fix if one of the declarations should be `const`. It's
                    // too hard to know how the developer would want to automatically resolve the issue.
                    varDeclParent.declarations.length === 1 &&
 
                    // Don't do a fix unless the variable is initialized (or it's in a for-in or for-of loop)
                    (varDeclParent.parent.type === "ForInStatement" || varDeclParent.parent.type === "ForOfStatement" || varDeclParent.declarations[0].init) &&
 
                    // If options.destucturing is "all", then this warning will not occur unless
                    // every assignment in the destructuring should be const. In that case, it's safe
                    // to apply the fix.
                    nodesToReport.length === nodes.length;
 
                nodesToReport.forEach(node => {
                    context.report({
                        node,
                        message: "'{{name}}' is never reassigned. Use 'const' instead.",
                        data: node,
                        fix: shouldFix ? fixer => fixer.replaceText(sourceCode.getFirstToken(varDeclParent), "const") : null
                    });
                });
            }
        }
 
        return {
            "Program:exit"() {
                groupByDestructuring(variables, ignoreReadBeforeAssign).forEach(checkGroup);
            },
 
            VariableDeclaration(node) {
                if (node.kind === "let" && !isInitOfForStatement(node)) {
                    pushAll(variables, context.getDeclaredVariables(node));
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/prefer-destructuring.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/prefer-destructuring.js

Statements: 14.63% (6 / 41)      Branches: 0% (0 / 34)      Functions: 0% (0 / 6)      Lines: 14.63% (6 / 41)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177                    1                                                                                                                                         1                     1                               1                                                               1                                         1                                  
/**
 * @fileoverview Prefer destructuring from arrays and objects
 * @author Alex LaFroscia
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require destructuring from arrays and/or objects",
            category: "ECMAScript 6",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    array: {
                        type: "boolean"
                    },
                    object: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            },
            {
                type: "object",
                properties: {
                    enforceForRenamedProperties: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
    create(context) {
 
        let checkArrays = true;
        let checkObjects = true;
        let enforceForRenamedProperties = false;
        const enabledTypes = context.options[0];
        const additionalOptions = context.options[1];
 
        if (enabledTypes) {
            if (typeof enabledTypes.array !== "undefined") {
                checkArrays = enabledTypes.array;
            }
 
            if (typeof enabledTypes.object !== "undefined") {
                checkObjects = enabledTypes.object;
            }
        }
 
        if (additionalOptions) {
            if (typeof additionalOptions.enforceForRenamedProperties !== "undefined") {
                enforceForRenamedProperties = additionalOptions.enforceForRenamedProperties;
            }
        }
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Determines if the given node node is accessing an array index
         *
         * This is used to differentiate array index access from object property
         * access.
         *
         * @param {ASTNode} node the node to evaluate
         * @returns {boolean} whether or not the node is an integer
         */
        function isArrayIndexAccess(node) {
            return Number.isInteger(node.property.value);
        }
 
        /**
         * Report that the given node should use destructuring
         *
         * @param {ASTNode} reportNode the node to report
         * @param {string} type the type of destructuring that should have been done
         * @returns {void}
         */
        function report(reportNode, type) {
            context.report({ node: reportNode, message: "Use {{type}} destructuring.", data: { type } });
        }
 
        /**
         * Check that the `prefer-destructuring` rules are followed based on the
         * given left- and right-hand side of the assignment.
         *
         * Pulled out into a separate method so that VariableDeclarators and
         * AssignmentExpressions can share the same verification logic.
         *
         * @param {ASTNode} leftNode the left-hand side of the assignment
         * @param {ASTNode} rightNode the right-hand side of the assignment
         * @param {ASTNode} reportNode the node to report the error on
         * @returns {void}
         */
        function performCheck(leftNode, rightNode, reportNode) {
            if (rightNode.type !== "MemberExpression") {
                return;
            }
 
            if (checkArrays && isArrayIndexAccess(rightNode)) {
                report(reportNode, "array");
                return;
            }
 
            if (checkObjects && enforceForRenamedProperties) {
                report(reportNode, "object");
                return;
            }
 
            if (checkObjects) {
                const property = rightNode.property;
 
                if ((property.type === "Literal" && leftNode.name === property.value) ||
                    (property.type === "Identifier" && leftNode.name === property.name)) {
                    report(reportNode, "object");
                }
            }
        }
 
        /**
         * Check if a given variable declarator is coming from an property access
         * that should be using destructuring instead
         *
         * @param {ASTNode} node the variable declarator to check
         * @returns {void}
         */
        function checkVariableDeclarator(node) {
 
            // Skip if variable is declared without assignment
            if (!node.init) {
                return;
            }
 
            // We only care about member expressions past this point
            if (node.init.type !== "MemberExpression") {
                return;
            }
 
            performCheck(node.id, node.init, node);
        }
 
        /**
         * Run the `prefer-destructuring` check on an AssignmentExpression
         *
         * @param {ASTNode} node the AssignmentExpression node
         * @returns {void}
         */
        function checkAssigmentExpression(node) {
            if (node.operator === "=") {
                performCheck(node.left, node.right, node);
            }
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            VariableDeclarator: checkVariableDeclarator,
            AssignmentExpression: checkAssigmentExpression
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/prefer-numeric-literals.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/prefer-numeric-literals.js

Statements: 7.69% (1 / 13)      Branches: 0% (0 / 10)      Functions: 0% (0 / 3)      Lines: 7.69% (1 / 13)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83                      1                                                                                                                                              
/**
 * @fileoverview Rule to disallow `parseInt()` in favor of binary, octal, and hexadecimal literals
 * @author Annie Zhang, Henry Zhu
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow `parseInt()` in favor of binary, octal, and hexadecimal literals",
            category: "ECMAScript 6",
            recommended: false
        },
 
        schema: [],
 
        fixable: "code"
    },
 
    create(context) {
        const radixMap = {
            2: "binary",
            8: "octal",
            16: "hexadecimal"
        };
 
        const prefixMap = {
            2: "0b",
            8: "0o",
            16: "0x"
        };
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
 
            CallExpression(node) {
 
                // doesn't check parseInt() if it doesn't have a radix argument
                if (node.arguments.length !== 2) {
                    return;
                }
 
                // only error if the radix is 2, 8, or 16
                const radixName = radixMap[node.arguments[1].value];
 
                if (node.callee.type === "Identifier" &&
                    node.callee.name === "parseInt" &&
                    radixName &&
                    node.arguments[0].type === "Literal"
                ) {
                    context.report({
                        node,
                        message: "Use {{radixName}} literals instead of parseInt().",
                        data: {
                            radixName
                        },
                        fix(fixer) {
                            const newPrefix = prefixMap[node.arguments[1].value];
 
                            if (+(newPrefix + node.arguments[0].value) !== parseInt(node.arguments[0].value, node.arguments[1].value)) {
 
                                // If the newly-produced literal would be invalid, (e.g. 0b1234),
                                // or it would yield an incorrect parseInt result for some other reason, don't make a fix.
                                return null;
                            }
                            return fixer.replaceText(node, prefixMap[node.arguments[1].value] + node.arguments[0].value);
                        }
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/prefer-promise-reject-errors.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/prefer-promise-reject-errors.js

Statements: 21.05% (4 / 19)      Branches: 0% (0 / 29)      Functions: 0% (0 / 5)      Lines: 21.05% (4 / 19)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126            1           1                                                               1                                         1                                                                                                                        
/**
 * @fileoverview restrict values that can be used as Promise rejection reasons
 * @author Teddy Katz
 */
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require using Error objects as Promise rejection reasons",
            category: "Best Practices",
            recommended: false
        },
        fixable: null,
        schema: [
            {
                type: "object",
                properties: {
                    allowEmptyReject: { type: "boolean" }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        const ALLOW_EMPTY_REJECT = context.options.length && context.options[0].allowEmptyReject;
 
        //----------------------------------------------------------------------
        // Helpers
        //----------------------------------------------------------------------
 
        /**
        * Checks the argument of a reject() or Promise.reject() CallExpression, and reports it if it can't be an Error
        * @param {ASTNode} callExpression A CallExpression node which is used to reject a Promise
        * @returns {void}
        */
        function checkRejectCall(callExpression) {
            if (!callExpression.arguments.length && ALLOW_EMPTY_REJECT) {
                return;
            }
            if (
                !callExpression.arguments.length ||
                !astUtils.couldBeError(callExpression.arguments[0]) ||
                callExpression.arguments[0].type === "Identifier" && callExpression.arguments[0].name === "undefined"
            ) {
                context.report({
                    node: callExpression,
                    message: "Expected the Promise rejection reason to be an Error."
                });
            }
        }
 
        /**
        * Determines whether a function call is a Promise.reject() call
        * @param {ASTNode} node A CallExpression node
        * @returns {boolean} `true` if the call is a Promise.reject() call
        */
        function isPromiseRejectCall(node) {
            return node.callee.type === "MemberExpression" &&
                node.callee.object.type === "Identifier" && node.callee.object.name === "Promise" &&
                node.callee.property.type === "Identifier" && node.callee.property.name === "reject";
        }
 
        //----------------------------------------------------------------------
        // Public
        //----------------------------------------------------------------------
 
        return {
 
            // Check `Promise.reject(value)` calls.
            CallExpression(node) {
                if (isPromiseRejectCall(node)) {
                    checkRejectCall(node);
                }
            },
 
            /*
             * Check for `new Promise((resolve, reject) => {})`, and check for reject() calls.
             * This function is run on "NewExpression:exit" instead of "NewExpression" to ensure that
             * the nodes in the expression already have the `parent` property.
             */
            "NewExpression:exit"(node) {
                if (
                    node.callee.type === "Identifier" && node.callee.name === "Promise" &&
                    node.arguments.length && astUtils.isFunction(node.arguments[0]) &&
                    node.arguments[0].params.length > 1 && node.arguments[0].params[1].type === "Identifier"
                ) {
                    context.getDeclaredVariables(node.arguments[0])
 
                        /*
                        * Find the first variable that matches the second parameter's name.
                        * If the first parameter has the same name as the second parameter, then the variable will actually
                        * be "declared" when the first parameter is evaluated, but then it will be immediately overwritten
                        * by the second parameter. It's not possible for an expression with the variable to be evaluated before
                        * the variable is overwritten, because functions with duplicate parameters cannot have destructuring or
                        * default assignments in their parameter lists. Therefore, it's not necessary to explicitly account for
                        * this case.
                        */
                        .find(variable => variable.name === node.arguments[0].params[1].name)
 
                        // Get the references to that variable.
                        .references
 
                        // Only check the references that read the parameter's value.
                        .filter(ref => ref.isRead())
 
                        // Only check the references that are used as the callee in a function call, e.g. `reject(foo)`.
                        .filter(ref => ref.identifier.parent.type === "CallExpression" && ref.identifier === ref.identifier.parent.callee)
 
                        // Check the argument of the function call to determine whether it's an Error.
                        .forEach(ref => checkRejectCall(ref.identifier.parent));
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/prefer-reflect.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/prefer-reflect.js

Statements: 11.11% (2 / 18)      Branches: 0% (0 / 18)      Functions: 0% (0 / 4)      Lines: 11.11% (2 / 18)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117                      1                                                                                                                                                 1                                                                
/**
 * @fileoverview Rule to suggest using "Reflect" api over Function/Object methods
 * @author Keith Cirkel <http://keithcirkel.co.uk>
 * @deprecated in ESLint v3.9.0
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require `Reflect` methods where applicable",
            category: "ECMAScript 6",
            recommended: false,
            replacedBy: []
        },
 
        deprecated: true,
 
        schema: [
            {
                type: "object",
                properties: {
                    exceptions: {
                        type: "array",
                        items: {
                            enum: [
                                "apply",
                                "call",
                                "delete",
                                "defineProperty",
                                "getOwnPropertyDescriptor",
                                "getPrototypeOf",
                                "setPrototypeOf",
                                "isExtensible",
                                "getOwnPropertyNames",
                                "preventExtensions"
                            ]
                        },
                        uniqueItems: true
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const existingNames = {
            apply: "Function.prototype.apply",
            call: "Function.prototype.call",
            defineProperty: "Object.defineProperty",
            getOwnPropertyDescriptor: "Object.getOwnPropertyDescriptor",
            getPrototypeOf: "Object.getPrototypeOf",
            setPrototypeOf: "Object.setPrototypeOf",
            isExtensible: "Object.isExtensible",
            getOwnPropertyNames: "Object.getOwnPropertyNames",
            preventExtensions: "Object.preventExtensions"
        };
 
        const reflectSubsitutes = {
            apply: "Reflect.apply",
            call: "Reflect.apply",
            defineProperty: "Reflect.defineProperty",
            getOwnPropertyDescriptor: "Reflect.getOwnPropertyDescriptor",
            getPrototypeOf: "Reflect.getPrototypeOf",
            setPrototypeOf: "Reflect.setPrototypeOf",
            isExtensible: "Reflect.isExtensible",
            getOwnPropertyNames: "Reflect.getOwnPropertyNames",
            preventExtensions: "Reflect.preventExtensions"
        };
 
        const exceptions = (context.options[0] || {}).exceptions || [];
 
        /**
         * Reports the Reflect violation based on the `existing` and `substitute`
         * @param {Object} node The node that violates the rule.
         * @param {string} existing The existing method name that has been used.
         * @param {string} substitute The Reflect substitute that should be used.
         * @returns {void}
         */
        function report(node, existing, substitute) {
            context.report({ node, message: "Avoid using {{existing}}, instead use {{substitute}}.", data: {
                existing,
                substitute
            } });
        }
 
        return {
            CallExpression(node) {
                const methodName = (node.callee.property || {}).name;
                const isReflectCall = (node.callee.object || {}).name === "Reflect";
                const hasReflectSubsitute = reflectSubsitutes.hasOwnProperty(methodName);
                const userConfiguredException = exceptions.indexOf(methodName) !== -1;
 
                if (hasReflectSubsitute && !isReflectCall && !userConfiguredException) {
                    report(node, existingNames[methodName], reflectSubsitutes[methodName]);
                }
            },
            UnaryExpression(node) {
                const isDeleteOperator = node.operator === "delete";
                const targetsIdentifier = node.argument.type === "Identifier";
                const userConfiguredException = exceptions.indexOf("delete") !== -1;
 
                if (isDeleteOperator && !targetsIdentifier && !userConfiguredException) {
                    report(node, "the delete keyword", "Reflect.deleteProperty");
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/prefer-rest-params.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/prefer-rest-params.js

Statements: 31.58% (6 / 19)      Branches: 0% (0 / 9)      Functions: 0% (0 / 5)      Lines: 31.58% (6 / 19)      Ignored: 1 statement     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111                                1                             1                           1                             1                                     1                         1                                    
/**
 * @fileoverview Rule to
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Gets the variable object of `arguments` which is defined implicitly.
 * @param {escope.Scope} scope - A scope to get.
 * @returns {escope.Variable} The found variable object.
 */
function getVariableOfArguments(scope) {
    const variables = scope.variables;
 
    for (let i = 0; i < variables.length; ++i) {
        const variable = variables[i];
 
        if (variable.name === "arguments") {
 
            // If there was a parameter which is named "arguments", the implicit "arguments" is not defined.
            // So does fast return with null.
            return (variable.identifiers.length === 0) ? variable : null;
        }
    }
 
    /* istanbul ignore next : unreachable */
    return null;
}
 
/**
 * Checks if the given reference is not normal member access.
 *
 * - arguments         .... true    // not member access
 * - arguments[i]      .... true    // computed member access
 * - arguments[0]      .... true    // computed member access
 * - arguments.length  .... false   // normal member access
 *
 * @param {escope.Reference} reference - The reference to check.
 * @returns {boolean} `true` if the reference is not normal member access.
 */
function isNotNormalMemberAccess(reference) {
    const id = reference.identifier;
    const parent = id.parent;
 
    return !(
        parent.type === "MemberExpression" &&
        parent.object === id &&
        !parent.computed
    );
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require rest parameters instead of `arguments`",
            category: "ECMAScript 6",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        /**
         * Reports a given reference.
         *
         * @param {escope.Reference} reference - A reference to report.
         * @returns {void}
         */
        function report(reference) {
            context.report({
                node: reference.identifier,
                loc: reference.identifier.loc,
                message: "Use the rest parameters instead of 'arguments'."
            });
        }
 
        /**
         * Reports references of the implicit `arguments` variable if exist.
         *
         * @returns {void}
         */
        function checkForArguments() {
            const argumentsVar = getVariableOfArguments(context.getScope());
 
            if (argumentsVar) {
                argumentsVar
                    .references
                    .filter(isNotNormalMemberAccess)
                    .forEach(report);
            }
        }
 
        return {
            "FunctionDeclaration:exit": checkForArguments,
            "FunctionExpression:exit": checkForArguments
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/prefer-spread.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/prefer-spread.js

Statements: 16.13% (5 / 31)      Branches: 0% (0 / 25)      Functions: 0% (0 / 6)      Lines: 16.67% (5 / 30)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122              1                     1                                     1                                                 1                     1                                                                                                
/**
 * @fileoverview A rule to suggest using of the spread operator instead of `.apply()`.
 * @author Toru Nagashima
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks whether or not a node is a `.apply()` for variadic.
 * @param {ASTNode} node - A CallExpression node to check.
 * @returns {boolean} Whether or not the node is a `.apply()` for variadic.
 */
function isVariadicApplyCalling(node) {
    return (
        node.callee.type === "MemberExpression" &&
        node.callee.property.type === "Identifier" &&
        node.callee.property.name === "apply" &&
        node.callee.computed === false &&
        node.arguments.length === 2 &&
        node.arguments[1].type !== "ArrayExpression" &&
        node.arguments[1].type !== "SpreadElement"
    );
}
 
/**
 * Checks whether or not the tokens of two given nodes are same.
 * @param {ASTNode} left - A node 1 to compare.
 * @param {ASTNode} right - A node 2 to compare.
 * @param {SourceCode} sourceCode - The ESLint source code object.
 * @returns {boolean} the source code for the given node.
 */
function equalTokens(left, right, sourceCode) {
    const tokensL = sourceCode.getTokens(left);
    const tokensR = sourceCode.getTokens(right);
 
    if (tokensL.length !== tokensR.length) {
        return false;
    }
    for (let i = 0; i < tokensL.length; ++i) {
        if (tokensL[i].type !== tokensR[i].type ||
            tokensL[i].value !== tokensR[i].value
        ) {
            return false;
        }
    }
 
    return true;
}
 
/**
 * Checks whether or not `thisArg` is not changed by `.apply()`.
 * @param {ASTNode|null} expectedThis - The node that is the owner of the applied function.
 * @param {ASTNode} thisArg - The node that is given to the first argument of the `.apply()`.
 * @param {RuleContext} context - The ESLint rule context object.
 * @returns {boolean} Whether or not `thisArg` is not changed by `.apply()`.
 */
function isValidThisArg(expectedThis, thisArg, context) {
    if (!expectedThis) {
        return astUtils.isNullOrUndefined(thisArg);
    }
    return equalTokens(expectedThis, thisArg, context);
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require spread operators instead of `.apply()`",
            category: "ECMAScript 6",
            recommended: false
        },
 
        schema: [],
 
        fixable: "code"
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        return {
            CallExpression(node) {
                if (!isVariadicApplyCalling(node)) {
                    return;
                }
 
                const applied = node.callee.object;
                const expectedThis = (applied.type === "MemberExpression") ? applied.object : null;
                const thisArg = node.arguments[0];
 
                if (isValidThisArg(expectedThis, thisArg, sourceCode)) {
                    context.report({
                        node,
                        message: "Use the spread operator instead of '.apply()'.",
                        fix(fixer) {
                            if (expectedThis && expectedThis.type !== "Identifier") {
 
                                // Don't fix cases where the `this` value could be a computed expression.
                                return null;
                            }
 
                            const propertyDot = sourceCode.getFirstTokenBetween(applied, node.callee.property, token => token.value === ".");
 
                            return fixer.replaceTextRange([propertyDot.range[0], node.range[1]], `(...${sourceCode.getText(node.arguments[1])})`);
                        }
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/prefer-template.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/prefer-template.js

Statements: 16.18% (11 / 68)      Branches: 0% (0 / 57)      Functions: 0% (0 / 12)      Lines: 16.67% (11 / 66)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230                      1                     1                 1                       1                           1                           1                             1                           1                                             1                           1                                                                                                                 1                                                                      
/**
 * @fileoverview A rule to suggest using template literals instead of string concatenation.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks whether or not a given node is a concatenation.
 * @param {ASTNode} node - A node to check.
 * @returns {boolean} `true` if the node is a concatenation.
 */
function isConcatenation(node) {
    return node.type === "BinaryExpression" && node.operator === "+";
}
 
/**
 * Gets the top binary expression node for concatenation in parents of a given node.
 * @param {ASTNode} node - A node to get.
 * @returns {ASTNode} the top binary expression node in parents of a given node.
 */
function getTopConcatBinaryExpression(node) {
    while (isConcatenation(node.parent)) {
        node = node.parent;
    }
    return node;
}
 
/**
* Checks whether or not a given binary expression has string literals.
* @param {ASTNode} node - A node to check.
* @returns {boolean} `true` if the node has string literals.
*/
function hasStringLiteral(node) {
    if (isConcatenation(node)) {
 
        // `left` is deeper than `right` normally.
        return hasStringLiteral(node.right) || hasStringLiteral(node.left);
    }
    return astUtils.isStringLiteral(node);
}
 
/**
 * Checks whether or not a given binary expression has non string literals.
 * @param {ASTNode} node - A node to check.
 * @returns {boolean} `true` if the node has non string literals.
 */
function hasNonStringLiteral(node) {
    if (isConcatenation(node)) {
 
        // `left` is deeper than `right` normally.
        return hasNonStringLiteral(node.right) || hasNonStringLiteral(node.left);
    }
    return !astUtils.isStringLiteral(node);
}
 
/**
* Determines whether a given node will start with a template curly expression (`${}`) when being converted to a template literal.
* @param {ASTNode} node The node that will be fixed to a template literal
* @returns {boolean} `true` if the node will start with a template curly.
*/
function startsWithTemplateCurly(node) {
    if (node.type === "BinaryExpression") {
        return startsWithTemplateCurly(node.left);
    }
    if (node.type === "TemplateLiteral") {
        return node.expressions.length && node.quasis.length && node.quasis[0].start === node.quasis[0].end;
    }
    return node.type !== "Literal" || typeof node.value !== "string";
}
 
/**
* Determines whether a given node end with a template curly expression (`${}`) when being converted to a template literal.
* @param {ASTNode} node The node that will be fixed to a template literal
* @returns {boolean} `true` if the node will end with a template curly.
*/
function endsWithTemplateCurly(node) {
    if (node.type === "BinaryExpression") {
        return startsWithTemplateCurly(node.right);
    }
    if (node.type === "TemplateLiteral") {
        return node.expressions.length && node.quasis.length && node.quasis[node.quasis.length - 1].start === node.quasis[node.quasis.length - 1].end;
    }
    return node.type !== "Literal" || typeof node.value !== "string";
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require template literals instead of string concatenation",
            category: "ECMAScript 6",
            recommended: false
        },
 
        schema: [],
 
        fixable: "code"
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
        let done = Object.create(null);
 
        /**
        * Gets the non-token text between two nodes, ignoring any other tokens that appear between the two tokens.
        * @param {ASTNode} node1 The first node
        * @param {ASTNode} node2 The second node
        * @returns {string} The text between the nodes, excluding other tokens
        */
        function getTextBetween(node1, node2) {
            const allTokens = [node1].concat(sourceCode.getTokensBetween(node1, node2)).concat(node2);
            const sourceText = sourceCode.getText();
 
            return allTokens.slice(0, -1).reduce((accumulator, token, index) => accumulator + sourceText.slice(token.range[1], allTokens[index + 1].range[0]), "");
        }
 
        /**
        * Returns a template literal form of the given node.
        * @param {ASTNode} currentNode A node that should be converted to a template literal
        * @param {string} textBeforeNode Text that should appear before the node
        * @param {string} textAfterNode Text that should appear after the node
        * @returns {string} A string form of this node, represented as a template literal
        */
        function getTemplateLiteral(currentNode, textBeforeNode, textAfterNode) {
            if (currentNode.type === "Literal" && typeof currentNode.value === "string") {
 
                // If the current node is a string literal, escape any instances of ${ or ` to prevent them from being interpreted
                // as a template placeholder. However, if the code already contains a backslash before the ${ or `
                // for some reason, don't add another backslash, because that would change the meaning of the code (it would cause
                // an actual backslash character to appear before the dollar sign).
                return `\`${currentNode.raw.slice(1, -1).replace(/\\*(\${|`)/g, matched => {
                    if (matched.lastIndexOf("\\") % 2) {
                        return `\\${matched}`;
                    }
                    return matched;
 
                // Unescape any quotes that appear in the original Literal that no longer need to be escaped.
                }).replace(new RegExp(`\\\\${currentNode.raw[0]}`, "g"), currentNode.raw[0])}\``;
            }
 
            if (currentNode.type === "TemplateLiteral") {
                return sourceCode.getText(currentNode);
            }
 
            if (isConcatenation(currentNode) && hasStringLiteral(currentNode) && hasNonStringLiteral(currentNode)) {
                const plusSign = sourceCode.getFirstTokenBetween(currentNode.left, currentNode.right, token => token.value === "+");
                const textBeforePlus = getTextBetween(currentNode.left, plusSign);
                const textAfterPlus = getTextBetween(plusSign, currentNode.right);
                const leftEndsWithCurly = endsWithTemplateCurly(currentNode.left);
                const rightStartsWithCurly = startsWithTemplateCurly(currentNode.right);
 
                if (leftEndsWithCurly) {
 
                    // If the left side of the expression ends with a template curly, add the extra text to the end of the curly bracket.
                    // `foo${bar}` /* comment */ + 'baz' --> `foo${bar /* comment */  }${baz}`
                    return getTemplateLiteral(currentNode.left, textBeforeNode, textBeforePlus + textAfterPlus).slice(0, -1) +
                        getTemplateLiteral(currentNode.right, null, textAfterNode).slice(1);
                }
                if (rightStartsWithCurly) {
 
                    // Otherwise, if the right side of the expression starts with a template curly, add the text there.
                    // 'foo' /* comment */ + `${bar}baz` --> `foo${ /* comment */  bar}baz`
                    return getTemplateLiteral(currentNode.left, textBeforeNode, null).slice(0, -1) +
                        getTemplateLiteral(currentNode.right, textBeforePlus + textAfterPlus, textAfterNode).slice(1);
                }
 
                // Otherwise, these nodes should not be combined into a template curly, since there is nowhere to put
                // the text between them.
                return `${getTemplateLiteral(currentNode.left, textBeforeNode, null)}${textBeforePlus}+${textAfterPlus}${getTemplateLiteral(currentNode.right, textAfterNode, null)}`;
            }
 
            return `\`\${${textBeforeNode || ""}${sourceCode.getText(currentNode)}${textAfterNode || ""}}\``;
        }
 
        /**
         * Reports if a given node is string concatenation with non string literals.
         *
         * @param {ASTNode} node - A node to check.
         * @returns {void}
         */
        function checkForStringConcat(node) {
            if (!astUtils.isStringLiteral(node) || !isConcatenation(node.parent)) {
                return;
            }
 
            const topBinaryExpr = getTopConcatBinaryExpression(node.parent);
 
            // Checks whether or not this node had been checked already.
            if (done[topBinaryExpr.range[0]]) {
                return;
            }
            done[topBinaryExpr.range[0]] = true;
 
            if (hasNonStringLiteral(topBinaryExpr)) {
                context.report({
                    node: topBinaryExpr,
                    message: "Unexpected string concatenation.",
                    fix(fixer) {
                        return fixer.replaceText(topBinaryExpr, getTemplateLiteral(topBinaryExpr, null, null));
                    }
                });
            }
        }
 
        return {
            Program() {
                done = Object.create(null);
            },
 
            Literal: checkForStringConcat,
            TemplateLiteral: checkForStringConcat
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/quote-props.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/quote-props.js

Statements: 10.84% (9 / 83)      Branches: 0% (0 / 107)      Functions: 0% (0 / 10)      Lines: 10.84% (9 / 83)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298                    1             1                                                                                                                                           1                       1                     1                 1                               1                                                                                                             1                                     1                                                                                                                                                                                
/**
 * @fileoverview Rule to flag non-quoted property names in object literals.
 * @author Mathias Bynens <http://mathiasbynens.be/>
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const espree = require("espree"),
    keywords = require("../util/keywords");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require quotes around object literal property names",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: {
            anyOf: [
                {
                    type: "array",
                    items: [
                        {
                            enum: ["always", "as-needed", "consistent", "consistent-as-needed"]
                        }
                    ],
                    minItems: 0,
                    maxItems: 1
                },
                {
                    type: "array",
                    items: [
                        {
                            enum: ["always", "as-needed", "consistent", "consistent-as-needed"]
                        },
                        {
                            type: "object",
                            properties: {
                                keywords: {
                                    type: "boolean"
                                },
                                unnecessary: {
                                    type: "boolean"
                                },
                                numbers: {
                                    type: "boolean"
                                }
                            },
                            additionalProperties: false
                        }
                    ],
                    minItems: 0,
                    maxItems: 2
                }
            ]
        },
 
        fixable: "code"
    },
 
    create(context) {
 
        const MODE = context.options[0],
            KEYWORDS = context.options[1] && context.options[1].keywords,
            CHECK_UNNECESSARY = !context.options[1] || context.options[1].unnecessary !== false,
            NUMBERS = context.options[1] && context.options[1].numbers,
 
            MESSAGE_UNNECESSARY = "Unnecessarily quoted property '{{property}}' found.",
            MESSAGE_UNQUOTED = "Unquoted property '{{property}}' found.",
            MESSAGE_NUMERIC = "Unquoted number literal '{{property}}' used as key.",
            MESSAGE_RESERVED = "Unquoted reserved word '{{property}}' used as key.",
            sourceCode = context.getSourceCode();
 
 
        /**
         * Checks whether a certain string constitutes an ES3 token
         * @param   {string} tokenStr - The string to be checked.
         * @returns {boolean} `true` if it is an ES3 token.
         */
        function isKeyword(tokenStr) {
            return keywords.indexOf(tokenStr) >= 0;
        }
 
        /**
         * Checks if an espree-tokenized key has redundant quotes (i.e. whether quotes are unnecessary)
         * @param   {string} rawKey The raw key value from the source
         * @param   {espreeTokens} tokens The espree-tokenized node key
         * @param   {boolean} [skipNumberLiterals=false] Indicates whether number literals should be checked
         * @returns {boolean} Whether or not a key has redundant quotes.
         * @private
         */
        function areQuotesRedundant(rawKey, tokens, skipNumberLiterals) {
            return tokens.length === 1 && tokens[0].start === 0 && tokens[0].end === rawKey.length &&
                (["Identifier", "Keyword", "Null", "Boolean"].indexOf(tokens[0].type) >= 0 ||
                (tokens[0].type === "Numeric" && !skipNumberLiterals && String(+tokens[0].value) === tokens[0].value));
        }
 
        /**
        * Returns a string representation of a property node with quotes removed
        * @param {ASTNode} key Key AST Node, which may or may not be quoted
        * @returns {string} A replacement string for this property
        */
        function getUnquotedKey(key) {
            return key.type === "Identifier" ? key.name : key.value;
        }
 
        /**
        * Returns a string representation of a property node with quotes added
        * @param {ASTNode} key Key AST Node, which may or may not be quoted
        * @returns {string} A replacement string for this property
        */
        function getQuotedKey(key) {
            if (key.type === "Literal" && typeof key.value === "string") {
 
                // If the key is already a string literal, don't replace the quotes with double quotes.
                return sourceCode.getText(key);
            }
 
            // Otherwise, the key is either an identifier or a number literal.
            return `"${key.type === "Identifier" ? key.name : key.value}"`;
        }
 
        /**
         * Ensures that a property's key is quoted only when necessary
         * @param   {ASTNode} node Property AST node
         * @returns {void}
         */
        function checkUnnecessaryQuotes(node) {
            const key = node.key;
            let tokens;
 
            if (node.method || node.computed || node.shorthand) {
                return;
            }
 
            if (key.type === "Literal" && typeof key.value === "string") {
                try {
                    tokens = espree.tokenize(key.value);
                } catch (e) {
                    return;
                }
 
                if (tokens.length !== 1) {
                    return;
                }
 
                const isKeywordToken = isKeyword(tokens[0].value);
 
                if (isKeywordToken && KEYWORDS) {
                    return;
                }
 
                if (CHECK_UNNECESSARY && areQuotesRedundant(key.value, tokens, NUMBERS)) {
                    context.report({
                        node,
                        message: MESSAGE_UNNECESSARY,
                        data: { property: key.value },
                        fix: fixer => fixer.replaceText(key, getUnquotedKey(key))
                    });
                }
            } else if (KEYWORDS && key.type === "Identifier" && isKeyword(key.name)) {
                context.report({
                    node,
                    message: MESSAGE_RESERVED,
                    data: { property: key.name },
                    fix: fixer => fixer.replaceText(key, getQuotedKey(key))
                });
            } else if (NUMBERS && key.type === "Literal" && typeof key.value === "number") {
                context.report({
                    node,
                    message: MESSAGE_NUMERIC,
                    data: { property: key.value },
                    fix: fixer => fixer.replaceText(key, getQuotedKey(key))
                });
            }
        }
 
        /**
         * Ensures that a property's key is quoted
         * @param   {ASTNode} node Property AST node
         * @returns {void}
         */
        function checkOmittedQuotes(node) {
            const key = node.key;
 
            if (!node.method && !node.computed && !node.shorthand && !(key.type === "Literal" && typeof key.value === "string")) {
                context.report({
                    node,
                    message: MESSAGE_UNQUOTED,
                    data: { property: key.name || key.value },
                    fix: fixer => fixer.replaceText(key, getQuotedKey(key))
                });
            }
        }
 
        /**
         * Ensures that an object's keys are consistently quoted, optionally checks for redundancy of quotes
         * @param   {ASTNode} node Property AST node
         * @param   {boolean} checkQuotesRedundancy Whether to check quotes' redundancy
         * @returns {void}
         */
        function checkConsistency(node, checkQuotesRedundancy) {
            const quotedProps = [],
                unquotedProps = [];
            let keywordKeyName = null,
                necessaryQuotes = false;
 
            node.properties.forEach(property => {
                const key = property.key;
                let tokens;
 
                if (!key || property.method || property.computed || property.shorthand) {
                    return;
                }
 
                if (key.type === "Literal" && typeof key.value === "string") {
 
                    quotedProps.push(property);
 
                    if (checkQuotesRedundancy) {
                        try {
                            tokens = espree.tokenize(key.value);
                        } catch (e) {
                            necessaryQuotes = true;
                            return;
                        }
 
                        necessaryQuotes = necessaryQuotes || !areQuotesRedundant(key.value, tokens) || KEYWORDS && isKeyword(tokens[0].value);
                    }
                } else if (KEYWORDS && checkQuotesRedundancy && key.type === "Identifier" && isKeyword(key.name)) {
                    unquotedProps.push(property);
                    necessaryQuotes = true;
                    keywordKeyName = key.name;
                } else {
                    unquotedProps.push(property);
                }
            });
 
            if (checkQuotesRedundancy && quotedProps.length && !necessaryQuotes) {
                quotedProps.forEach(property => {
                    context.report({
                        node: property,
                        message: "Properties shouldn't be quoted as all quotes are redundant.",
                        fix: fixer => fixer.replaceText(property.key, getUnquotedKey(property.key))
                    });
                });
            } else if (unquotedProps.length && keywordKeyName) {
                unquotedProps.forEach(property => {
                    context.report({
                        node: property,
                        message: "Properties should be quoted as '{{property}}' is a reserved word.",
                        data: { property: keywordKeyName },
                        fix: fixer => fixer.replaceText(property.key, getQuotedKey(property.key))
                    });
                });
            } else if (quotedProps.length && unquotedProps.length) {
                unquotedProps.forEach(property => {
                    context.report({
                        node: property,
                        message: "Inconsistently quoted property '{{key}}' found.",
                        data: { key: property.key.name || property.key.value },
                        fix: fixer => fixer.replaceText(property.key, getQuotedKey(property.key))
                    });
                });
            }
        }
 
        return {
            Property(node) {
                if (MODE === "always" || !MODE) {
                    checkOmittedQuotes(node);
                }
                if (MODE === "as-needed") {
                    checkUnnecessaryQuotes(node);
                }
            },
            ObjectExpression(node) {
                if (MODE === "consistent") {
                    checkConsistency(node, false);
                }
                if (MODE === "consistent-as-needed") {
                    checkConsistency(node, true);
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/quotes.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/quotes.js

Statements: 16.13% (10 / 62)      Branches: 0% (0 / 75)      Functions: 0% (0 / 10)      Lines: 16.13% (10 / 62)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299                      1           1                                     1                     1                                             1           1                                                                                                                                           1                     1                             1                                                       1                                                                                                                                                                                                    
/**
 * @fileoverview A rule to choose between single and double quote marks
 * @author Matt DuVall <http://www.mattduvall.com/>, Brandon Payton
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Constants
//------------------------------------------------------------------------------
 
const QUOTE_SETTINGS = {
    double: {
        quote: "\"",
        alternateQuote: "'",
        description: "doublequote"
    },
    single: {
        quote: "'",
        alternateQuote: "\"",
        description: "singlequote"
    },
    backtick: {
        quote: "`",
        alternateQuote: "\"",
        description: "backtick"
    }
};
 
// An unescaped newline is a newline preceded by an even number of backslashes.
const UNESCAPED_LINEBREAK_PATTERN = new RegExp(String.raw`(^|[^\\])(\\\\)*[${Array.from(astUtils.LINEBREAKS).join("")}]`);
 
/**
 * Switches quoting of javascript string between ' " and `
 * escaping and unescaping as necessary.
 * Only escaping of the minimal set of characters is changed.
 * Note: escaping of newlines when switching from backtick to other quotes is not handled.
 * @param {string} str - A string to convert.
 * @returns {string} The string with changed quotes.
 * @private
 */
QUOTE_SETTINGS.double.convert =
QUOTE_SETTINGS.single.convert =
QUOTE_SETTINGS.backtick.convert = function(str) {
    const newQuote = this.quote;
    const oldQuote = str[0];
 
    if (newQuote === oldQuote) {
        return str;
    }
    return newQuote + str.slice(1, -1).replace(/\\(\${|\r\n?|\n|.)|["'`]|\${|(\r\n?|\n)/g, (match, escaped, newline) => {
        if (escaped === oldQuote || oldQuote === "`" && escaped === "${") {
            return escaped; // unescape
        }
        if (match === newQuote || newQuote === "`" && match === "${") {
            return `\\${match}`; // escape
        }
        if (newline && oldQuote === "`") {
            return "\\n"; // escape newlines
        }
        return match;
    }) + newQuote;
};
 
const AVOID_ESCAPE = "avoid-escape";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce the consistent use of either backticks, double, or single quotes",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "code",
 
        schema: [
            {
                enum: ["single", "double", "backtick"]
            },
            {
                anyOf: [
                    {
                        enum: ["avoid-escape"]
                    },
                    {
                        type: "object",
                        properties: {
                            avoidEscape: {
                                type: "boolean"
                            },
                            allowTemplateLiterals: {
                                type: "boolean"
                            }
                        },
                        additionalProperties: false
                    }
                ]
            }
        ]
    },
 
    create(context) {
 
        const quoteOption = context.options[0],
            settings = QUOTE_SETTINGS[quoteOption || "double"],
            options = context.options[1],
            allowTemplateLiterals = options && options.allowTemplateLiterals === true,
            sourceCode = context.getSourceCode();
        let avoidEscape = options && options.avoidEscape === true;
 
        // deprecated
        if (options === AVOID_ESCAPE) {
            avoidEscape = true;
        }
 
        /**
         * Determines if a given node is part of JSX syntax.
         *
         * This function returns `true` in the following cases:
         *
         * - `<div className="foo"></div>` ... If the literal is an attribute value, the parent of the literal is `JSXAttribute`.
         * - `<div>foo</div>` ... If the literal is a text content, the parent of the literal is `JSXElement`.
         *
         * In particular, this function returns `false` in the following cases:
         *
         * - `<div className={"foo"}></div>`
         * - `<div>{"foo"}</div>`
         *
         * In both cases, inside of the braces is handled as normal JavaScript.
         * The braces are `JSXExpressionContainer` nodes.
         *
         * @param {ASTNode} node The Literal node to check.
         * @returns {boolean} True if the node is a part of JSX, false if not.
         * @private
         */
        function isJSXLiteral(node) {
            return node.parent.type === "JSXAttribute" || node.parent.type === "JSXElement";
        }
 
        /**
         * Checks whether or not a given node is a directive.
         * The directive is a `ExpressionStatement` which has only a string literal.
         * @param {ASTNode} node - A node to check.
         * @returns {boolean} Whether or not the node is a directive.
         * @private
         */
        function isDirective(node) {
            return (
                node.type === "ExpressionStatement" &&
                node.expression.type === "Literal" &&
                typeof node.expression.value === "string"
            );
        }
 
        /**
         * Checks whether or not a given node is a part of directive prologues.
         * See also: http://www.ecma-international.org/ecma-262/6.0/#sec-directive-prologues-and-the-use-strict-directive
         * @param {ASTNode} node - A node to check.
         * @returns {boolean} Whether or not the node is a part of directive prologues.
         * @private
         */
        function isPartOfDirectivePrologue(node) {
            const block = node.parent.parent;
 
            if (block.type !== "Program" && (block.type !== "BlockStatement" || !astUtils.isFunction(block.parent))) {
                return false;
            }
 
            // Check the node is at a prologue.
            for (let i = 0; i < block.body.length; ++i) {
                const statement = block.body[i];
 
                if (statement === node.parent) {
                    return true;
                }
                if (!isDirective(statement)) {
                    break;
                }
            }
 
            return false;
        }
 
        /**
         * Checks whether or not a given node is allowed as non backtick.
         * @param {ASTNode} node - A node to check.
         * @returns {boolean} Whether or not the node is allowed as non backtick.
         * @private
         */
        function isAllowedAsNonBacktick(node) {
            const parent = node.parent;
 
            switch (parent.type) {
 
                // Directive Prologues.
                case "ExpressionStatement":
                    return isPartOfDirectivePrologue(node);
 
                // LiteralPropertyName.
                case "Property":
                case "MethodDefinition":
                    return parent.key === node && !parent.computed;
 
                // ModuleSpecifier.
                case "ImportDeclaration":
                case "ExportNamedDeclaration":
                case "ExportAllDeclaration":
                    return parent.source === node;
 
                // Others don't allow.
                default:
                    return false;
            }
        }
 
        return {
 
            Literal(node) {
                const val = node.value,
                    rawVal = node.raw;
                let isValid;
 
                if (settings && typeof val === "string") {
                    isValid = (quoteOption === "backtick" && isAllowedAsNonBacktick(node)) ||
                        isJSXLiteral(node) ||
                        astUtils.isSurroundedBy(rawVal, settings.quote);
 
                    if (!isValid && avoidEscape) {
                        isValid = astUtils.isSurroundedBy(rawVal, settings.alternateQuote) && rawVal.indexOf(settings.quote) >= 0;
                    }
 
                    if (!isValid) {
                        context.report({
                            node,
                            message: "Strings must use {{description}}.",
                            data: {
                                description: settings.description
                            },
                            fix(fixer) {
                                return fixer.replaceText(node, settings.convert(node.raw));
                            }
                        });
                    }
                }
            },
 
            TemplateLiteral(node) {
 
                // If backticks are expected or it's a tagged template, then this shouldn't throw an errors
                if (
                    allowTemplateLiterals ||
                    quoteOption === "backtick" ||
                    node.parent.type === "TaggedTemplateExpression" && node === node.parent.quasi
                ) {
                    return;
                }
 
                // A warning should be produced if the template literal only has one TemplateElement, and has no unescaped newlines.
                const shouldWarn = node.quasis.length === 1 && !UNESCAPED_LINEBREAK_PATTERN.test(node.quasis[0].value.raw);
 
                if (shouldWarn) {
                    context.report({
                        node,
                        message: "Strings must use {{description}}.",
                        data: {
                            description: settings.description
                        },
                        fix(fixer) {
                            if (isPartOfDirectivePrologue(node)) {
 
                                /*
                                 * TemplateLiterals in a directive prologue aren't actually directives, but if they're
                                 * in the directive prologue, then fixing them might turn them into directives and change
                                 * the behavior of the code.
                                 */
                                return null;
                            }
                            return fixer.replaceText(node, settings.convert(sourceCode.getText(node)));
                        }
                    });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/radix.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/radix.js

Statements: 20% (8 / 40)      Branches: 0% (0 / 33)      Functions: 0% (0 / 7)      Lines: 20% (8 / 40)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173                      1           1                 1                     1                                       1                         1               1                                                 1                                                                                                                                          
/**
 * @fileoverview Rule to flag use of parseInt without a radix argument
 * @author James Allardice
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const MODE_ALWAYS = "always",
    MODE_AS_NEEDED = "as-needed";
 
/**
 * Checks whether a given variable is shadowed or not.
 *
 * @param {escope.Variable} variable - A variable to check.
 * @returns {boolean} `true` if the variable is shadowed.
 */
function isShadowed(variable) {
    return variable.defs.length >= 1;
}
 
/**
 * Checks whether a given node is a MemberExpression of `parseInt` method or not.
 *
 * @param {ASTNode} node - A node to check.
 * @returns {boolean} `true` if the node is a MemberExpression of `parseInt`
 *      method.
 */
function isParseIntMethod(node) {
    return (
        node.type === "MemberExpression" &&
        !node.computed &&
        node.property.type === "Identifier" &&
        node.property.name === "parseInt"
    );
}
 
/**
 * Checks whether a given node is a valid value of radix or not.
 *
 * The following values are invalid.
 *
 * - A literal except numbers.
 * - undefined.
 *
 * @param {ASTNode} radix - A node of radix to check.
 * @returns {boolean} `true` if the node is valid.
 */
function isValidRadix(radix) {
    return !(
        (radix.type === "Literal" && typeof radix.value !== "number") ||
        (radix.type === "Identifier" && radix.name === "undefined")
    );
}
 
/**
 * Checks whether a given node is a default value of radix or not.
 *
 * @param {ASTNode} radix - A node of radix to check.
 * @returns {boolean} `true` if the node is the literal node of `10`.
 */
function isDefaultRadix(radix) {
    return radix.type === "Literal" && radix.value === 10;
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce the consistent use of the radix argument when using `parseInt()`",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [
            {
                enum: ["always", "as-needed"]
            }
        ]
    },
 
    create(context) {
        const mode = context.options[0] || MODE_ALWAYS;
 
        /**
         * Checks the arguments of a given CallExpression node and reports it if it
         * offends this rule.
         *
         * @param {ASTNode} node - A CallExpression node to check.
         * @returns {void}
         */
        function checkArguments(node) {
            const args = node.arguments;
 
            switch (args.length) {
                case 0:
                    context.report({
                        node,
                        message: "Missing parameters."
                    });
                    break;
 
                case 1:
                    if (mode === MODE_ALWAYS) {
                        context.report({
                            node,
                            message: "Missing radix parameter."
                        });
                    }
                    break;
 
                default:
                    if (mode === MODE_AS_NEEDED && isDefaultRadix(args[1])) {
                        context.report({
                            node,
                            message: "Redundant radix parameter."
                        });
                    } else if (!isValidRadix(args[1])) {
                        context.report({
                            node,
                            message: "Invalid radix parameter."
                        });
                    }
                    break;
            }
        }
 
        return {
            "Program:exit"() {
                const scope = context.getScope();
                let variable;
 
                // Check `parseInt()`
                variable = astUtils.getVariableByName(scope, "parseInt");
                if (!isShadowed(variable)) {
                    variable.references.forEach(reference => {
                        const node = reference.identifier;
 
                        if (astUtils.isCallee(node)) {
                            checkArguments(node.parent);
                        }
                    });
                }
 
                // Check `Number.parseInt()`
                variable = astUtils.getVariableByName(scope, "Number");
                if (!isShadowed(variable)) {
                    variable.references.forEach(reference => {
                        const node = reference.identifier.parent;
 
                        if (isParseIntMethod(node) && astUtils.isCallee(node)) {
                            checkArguments(node.parent);
                        }
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/require-await.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/require-await.js

Statements: 35.71% (5 / 14)      Branches: 0% (0 / 5)      Functions: 0% (0 / 5)      Lines: 35.71% (5 / 14)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97                      1                       1               1                                     1                           1                                                                
/**
 * @fileoverview Rule to disallow async functions which have no `await` expression.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Capitalize the 1st letter of the given text.
 *
 * @param {string} text - The text to capitalize.
 * @returns {string} The text that the 1st letter was capitalized.
 */
function capitalizeFirstLetter(text) {
    return text[0].toUpperCase() + text.slice(1);
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "disallow async functions which have no `await` expression",
            category: "Best Practices",
            recommended: false
        },
        schema: []
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
        let scopeInfo = null;
 
        /**
         * Push the scope info object to the stack.
         *
         * @returns {void}
         */
        function enterFunction() {
            scopeInfo = {
                upper: scopeInfo,
                hasAwait: false
            };
        }
 
        /**
         * Pop the top scope info object from the stack.
         * Also, it reports the function if needed.
         *
         * @param {ASTNode} node - The node to report.
         * @returns {void}
         */
        function exitFunction(node) {
            if (node.async && !scopeInfo.hasAwait && !astUtils.isEmptyFunction(node)) {
                context.report({
                    node,
                    loc: astUtils.getFunctionHeadLoc(node, sourceCode),
                    message: "{{name}} has no 'await' expression.",
                    data: {
                        name: capitalizeFirstLetter(
                            astUtils.getFunctionNameWithKind(node)
                        )
                    }
                });
            }
 
            scopeInfo = scopeInfo.upper;
        }
 
        return {
            FunctionDeclaration: enterFunction,
            FunctionExpression: enterFunction,
            ArrowFunctionExpression: enterFunction,
            "FunctionDeclaration:exit": exitFunction,
            "FunctionExpression:exit": exitFunction,
            "ArrowFunctionExpression:exit": exitFunction,
 
            AwaitExpression() {
                scopeInfo.hasAwait = true;
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/require-jsdoc.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/require-jsdoc.js

Statements: 16.67% (4 / 24)      Branches: 0% (0 / 19)      Functions: 0% (0 / 8)      Lines: 16.67% (4 / 24)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114            1                                                                                                   1                 1                             1                                                                  
/**
 * @fileoverview Rule to check for jsdoc presence.
 * @author Gyandeep Singh
 */
"use strict";
 
module.exports = {
    meta: {
        docs: {
            description: "require JSDoc comments",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    require: {
                        type: "object",
                        properties: {
                            ClassDeclaration: {
                                type: "boolean"
                            },
                            MethodDefinition: {
                                type: "boolean"
                            },
                            FunctionDeclaration: {
                                type: "boolean"
                            },
                            ArrowFunctionExpression: {
                                type: "boolean"
                            }
                        },
                        additionalProperties: false
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const source = context.getSourceCode();
        const DEFAULT_OPTIONS = {
            FunctionDeclaration: true,
            MethodDefinition: false,
            ClassDeclaration: false
        };
        const options = Object.assign(DEFAULT_OPTIONS, context.options[0] && context.options[0].require || {});
 
        /**
         * Report the error message
         * @param {ASTNode} node node to report
         * @returns {void}
         */
        function report(node) {
            context.report({ node, message: "Missing JSDoc comment." });
        }
 
        /**
         * Check if the jsdoc comment is present for class methods
         * @param {ASTNode} node node to examine
         * @returns {void}
         */
        function checkClassMethodJsDoc(node) {
            if (node.parent.type === "MethodDefinition") {
                const jsdocComment = source.getJSDocComment(node);
 
                if (!jsdocComment) {
                    report(node);
                }
            }
        }
 
        /**
         * Check if the jsdoc comment is present or not.
         * @param {ASTNode} node node to examine
         * @returns {void}
         */
        function checkJsDoc(node) {
            const jsdocComment = source.getJSDocComment(node);
 
            if (!jsdocComment) {
                report(node);
            }
        }
 
        return {
            FunctionDeclaration(node) {
                if (options.FunctionDeclaration) {
                    checkJsDoc(node);
                }
            },
            FunctionExpression(node) {
                if (options.MethodDefinition) {
                    checkClassMethodJsDoc(node);
                }
            },
            ClassDeclaration(node) {
                if (options.ClassDeclaration) {
                    checkJsDoc(node);
                }
            },
            ArrowFunctionExpression(node) {
                if (options.ArrowFunctionExpression && node.parent.type === "VariableDeclarator") {
                    checkJsDoc(node);
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/require-yield.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/require-yield.js

Statements: 21.43% (3 / 14)      Branches: 10% (1 / 10)      Functions: 0% (0 / 4)      Lines: 21.43% (3 / 14)      Ignored: 1 branch     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73                      1                                     1                       1                                                            
/**
 * @fileoverview Rule to flag the generator functions that does not have yield.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require generator functions to contain `yield`",
            category: "ECMAScript 6",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
        const stack = [];
 
        /**
         * If the node is a generator function, start counting `yield` keywords.
         * @param {Node} node - A function node to check.
         * @returns {void}
         */
        function beginChecking(node) {
            if (node.generator) {
                stack.push(0);
            }
        }
 
        /**
         * If the node is a generator function, end counting `yield` keywords, then
         * reports result.
         * @param {Node} node - A function node to check.
         * @returns {void}
         */
        function endChecking(node) {
            if (!node.generator) {
                return;
            }
 
            const countYield = stack.pop();
 
            if (countYield === 0 && node.body.body.length > 0) {
                context.report({ node, message: "This generator function does not have 'yield'." });
            }
        }
 
        return {
            FunctionDeclaration: beginChecking,
            "FunctionDeclaration:exit": endChecking,
            FunctionExpression: beginChecking,
            "FunctionExpression:exit": endChecking,
 
            // Increases the count of `yield` keyword.
            YieldExpression() {
 
                /* istanbul ignore else */
                if (stack.length > 0) {
                    stack[stack.length - 1] += 1;
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/rest-spread-spacing.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/rest-spread-spacing.js

Statements: 9.09% (2 / 22)      Branches: 0% (0 / 13)      Functions: 0% (0 / 4)      Lines: 9.09% (2 / 22)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109                      1                                                       1                                                                                                                                          
/**
 * @fileoverview Enforce spacing between rest and spread operators and their expressions.
 * @author Kai Cataldo
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce spacing between rest and spread operators and their expressions",
            category: "ECMAScript 6",
            recommended: false
        },
        fixable: "whitespace",
        schema: [
            {
                enum: ["always", "never"]
            }
        ]
    },
 
    create(context) {
        const sourceCode = context.getSourceCode(),
            alwaysSpace = context.options[0] === "always";
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Checks whitespace between rest/spread operators and their expressions
         * @param {ASTNode} node - The node to check
         * @returns {void}
         */
        function checkWhiteSpace(node) {
            const operator = sourceCode.getFirstToken(node),
                nextToken = sourceCode.getTokenAfter(operator),
                hasWhitespace = sourceCode.isSpaceBetweenTokens(operator, nextToken);
            let type;
 
            switch (node.type) {
                case "SpreadElement":
                    type = "spread";
                    break;
                case "RestElement":
                    type = "rest";
                    break;
                case "ExperimentalSpreadProperty":
                    type = "spread property";
                    break;
                case "ExperimentalRestProperty":
                    type = "rest property";
                    break;
                default:
                    return;
            }
 
            if (alwaysSpace && !hasWhitespace) {
                context.report({
                    node,
                    loc: {
                        line: operator.loc.end.line,
                        column: operator.loc.end.column
                    },
                    message: "Expected whitespace after {{type}} operator.",
                    data: {
                        type
                    },
                    fix(fixer) {
                        return fixer.replaceTextRange([operator.range[1], nextToken.range[0]], " ");
                    }
                });
            } else if (!alwaysSpace && hasWhitespace) {
                context.report({
                    node,
                    loc: {
                        line: operator.loc.end.line,
                        column: operator.loc.end.column
                    },
                    message: "Unexpected whitespace after {{type}} operator.",
                    data: {
                        type
                    },
                    fix(fixer) {
                        return fixer.removeRange([operator.range[1], nextToken.range[0]]);
                    }
                });
            }
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            SpreadElement: checkWhiteSpace,
            RestElement: checkWhiteSpace,
            ExperimentalSpreadProperty: checkWhiteSpace,
            ExperimentalRestProperty: checkWhiteSpace
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/semi-spacing.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/semi-spacing.js

Statements: 17.31% (9 / 52)      Branches: 0% (0 / 42)      Functions: 0% (0 / 13)      Lines: 17.31% (9 / 52)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213              1           1                                                                                             1                     1                     1                     1                     1                       1                                                                                                                                 1                                                              
/**
 * @fileoverview Validates spacing before and after semicolon
 * @author Mathias Schreck
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent spacing before and after semicolons",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                type: "object",
                properties: {
                    before: {
                        type: "boolean"
                    },
                    after: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        const config = context.options[0],
            sourceCode = context.getSourceCode();
        let requireSpaceBefore = false,
            requireSpaceAfter = true;
 
        if (typeof config === "object") {
            if (config.hasOwnProperty("before")) {
                requireSpaceBefore = config.before;
            }
            if (config.hasOwnProperty("after")) {
                requireSpaceAfter = config.after;
            }
        }
 
        /**
         * Checks if a given token has leading whitespace.
         * @param {Object} token The token to check.
         * @returns {boolean} True if the given token has leading space, false if not.
         */
        function hasLeadingSpace(token) {
            const tokenBefore = sourceCode.getTokenBefore(token);
 
            return tokenBefore && astUtils.isTokenOnSameLine(tokenBefore, token) && sourceCode.isSpaceBetweenTokens(tokenBefore, token);
        }
 
        /**
         * Checks if a given token has trailing whitespace.
         * @param {Object} token The token to check.
         * @returns {boolean} True if the given token has trailing space, false if not.
         */
        function hasTrailingSpace(token) {
            const tokenAfter = sourceCode.getTokenAfter(token);
 
            return tokenAfter && astUtils.isTokenOnSameLine(token, tokenAfter) && sourceCode.isSpaceBetweenTokens(token, tokenAfter);
        }
 
        /**
         * Checks if the given token is the last token in its line.
         * @param {Token} token The token to check.
         * @returns {boolean} Whether or not the token is the last in its line.
         */
        function isLastTokenInCurrentLine(token) {
            const tokenAfter = sourceCode.getTokenAfter(token);
 
            return !(tokenAfter && astUtils.isTokenOnSameLine(token, tokenAfter));
        }
 
        /**
         * Checks if the given token is the first token in its line
         * @param {Token} token The token to check.
         * @returns {boolean} Whether or not the token is the first in its line.
         */
        function isFirstTokenInCurrentLine(token) {
            const tokenBefore = sourceCode.getTokenBefore(token);
 
            return !(tokenBefore && astUtils.isTokenOnSameLine(token, tokenBefore));
        }
 
        /**
         * Checks if the next token of a given token is a closing parenthesis.
         * @param {Token} token The token to check.
         * @returns {boolean} Whether or not the next token of a given token is a closing parenthesis.
         */
        function isBeforeClosingParen(token) {
            const nextToken = sourceCode.getTokenAfter(token);
 
            return (nextToken && astUtils.isClosingBraceToken(nextToken) || astUtils.isClosingParenToken(nextToken));
        }
 
        /**
         * Reports if the given token has invalid spacing.
         * @param {Token} token The semicolon token to check.
         * @param {ASTNode} node The corresponding node of the token.
         * @returns {void}
         */
        function checkSemicolonSpacing(token, node) {
            if (astUtils.isSemicolonToken(token)) {
                const location = token.loc.start;
 
                if (hasLeadingSpace(token)) {
                    if (!requireSpaceBefore) {
                        context.report({
                            node,
                            loc: location,
                            message: "Unexpected whitespace before semicolon.",
                            fix(fixer) {
                                const tokenBefore = sourceCode.getTokenBefore(token);
 
                                return fixer.removeRange([tokenBefore.range[1], token.range[0]]);
                            }
                        });
                    }
                } else {
                    if (requireSpaceBefore) {
                        context.report({
                            node,
                            loc: location,
                            message: "Missing whitespace before semicolon.",
                            fix(fixer) {
                                return fixer.insertTextBefore(token, " ");
                            }
                        });
                    }
                }
 
                if (!isFirstTokenInCurrentLine(token) && !isLastTokenInCurrentLine(token) && !isBeforeClosingParen(token)) {
                    if (hasTrailingSpace(token)) {
                        if (!requireSpaceAfter) {
                            context.report({
                                node,
                                loc: location,
                                message: "Unexpected whitespace after semicolon.",
                                fix(fixer) {
                                    const tokenAfter = sourceCode.getTokenAfter(token);
 
                                    return fixer.removeRange([token.range[1], tokenAfter.range[0]]);
                                }
                            });
                        }
                    } else {
                        if (requireSpaceAfter) {
                            context.report({
                                node,
                                loc: location,
                                message: "Missing whitespace after semicolon.",
                                fix(fixer) {
                                    return fixer.insertTextAfter(token, " ");
                                }
                            });
                        }
                    }
                }
            }
        }
 
        /**
         * Checks the spacing of the semicolon with the assumption that the last token is the semicolon.
         * @param {ASTNode} node The node to check.
         * @returns {void}
         */
        function checkNode(node) {
            const token = sourceCode.getLastToken(node);
 
            checkSemicolonSpacing(token, node);
        }
 
        return {
            VariableDeclaration: checkNode,
            ExpressionStatement: checkNode,
            BreakStatement: checkNode,
            ContinueStatement: checkNode,
            DebuggerStatement: checkNode,
            ReturnStatement: checkNode,
            ThrowStatement: checkNode,
            ImportDeclaration: checkNode,
            ExportNamedDeclaration: checkNode,
            ExportAllDeclaration: checkNode,
            ExportDefaultDeclaration: checkNode,
            ForStatement(node) {
                if (node.init) {
                    checkSemicolonSpacing(sourceCode.getTokenAfter(node.init), node);
                }
 
                if (node.test) {
                    checkSemicolonSpacing(sourceCode.getTokenAfter(node.test), node);
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/semi.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/semi.js

Statements: 14.55% (8 / 55)      Branches: 0% (0 / 47)      Functions: 0% (0 / 10)      Lines: 14.55% (8 / 55)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230                    1 1           1                                                                                                                         1                                                                                   1                                               1                                   1                                                 1                                                                                    
/**
 * @fileoverview Rule to flag missing semicolons.
 * @author Nicholas C. Zakas
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const FixTracker = require("../util/fix-tracker");
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require or disallow semicolons instead of ASI",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "code",
 
        schema: {
            anyOf: [
                {
                    type: "array",
                    items: [
                        {
                            enum: ["never"]
                        }
                    ],
                    minItems: 0,
                    maxItems: 1
                },
                {
                    type: "array",
                    items: [
                        {
                            enum: ["always"]
                        },
                        {
                            type: "object",
                            properties: {
                                omitLastInOneLineBlock: { type: "boolean" }
                            },
                            additionalProperties: false
                        }
                    ],
                    minItems: 0,
                    maxItems: 2
                }
            ]
        }
    },
 
    create(context) {
 
        const OPT_OUT_PATTERN = /^[-[(/+`]/; // One of [(/+-`
        const options = context.options[1];
        const never = context.options[0] === "never",
            exceptOneLine = options && options.omitLastInOneLineBlock === true,
            sourceCode = context.getSourceCode();
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * Reports a semicolon error with appropriate location and message.
         * @param {ASTNode} node The node with an extra or missing semicolon.
         * @param {boolean} missing True if the semicolon is missing.
         * @returns {void}
         */
        function report(node, missing) {
            const lastToken = sourceCode.getLastToken(node);
            let message,
                fix,
                loc = lastToken.loc;
 
            if (!missing) {
                message = "Missing semicolon.";
                loc = loc.end;
                fix = function(fixer) {
                    return fixer.insertTextAfter(lastToken, ";");
                };
            } else {
                message = "Extra semicolon.";
                loc = loc.start;
                fix = function(fixer) {
 
                    // Expand the replacement range to include the surrounding
                    // tokens to avoid conflicting with no-extra-semi.
                    // https://github.com/eslint/eslint/issues/7928
                    return new FixTracker(fixer, sourceCode)
                        .retainSurroundingTokens(lastToken)
                        .remove(lastToken);
                };
            }
 
            context.report({
                node,
                loc,
                message,
                fix
            });
 
        }
 
        /**
         * Check if a semicolon is unnecessary, only true if:
         *   - next token is on a new line and is not one of the opt-out tokens
         *   - next token is a valid statement divider
         * @param {Token} lastToken last token of current node.
         * @returns {boolean} whether the semicolon is unnecessary.
         */
        function isUnnecessarySemicolon(lastToken) {
            if (!astUtils.isSemicolonToken(lastToken)) {
                return false;
            }
 
            const nextToken = sourceCode.getTokenAfter(lastToken);
 
            if (!nextToken) {
                return true;
            }
 
            const lastTokenLine = lastToken.loc.end.line;
            const nextTokenLine = nextToken.loc.start.line;
            const isOptOutToken = OPT_OUT_PATTERN.test(nextToken.value) && nextToken.value !== "++" && nextToken.value !== "--";
            const isDivider = (astUtils.isClosingBraceToken(nextToken) || astUtils.isSemicolonToken(nextToken));
 
            return (lastTokenLine !== nextTokenLine && !isOptOutToken) || isDivider;
        }
 
        /**
         * Checks a node to see if it's in a one-liner block statement.
         * @param {ASTNode} node The node to check.
         * @returns {boolean} whether the node is in a one-liner block statement.
         */
        function isOneLinerBlock(node) {
            const nextToken = sourceCode.getTokenAfter(node);
 
            if (!nextToken || nextToken.value !== "}") {
                return false;
            }
 
            const parent = node.parent;
 
            return parent && parent.type === "BlockStatement" &&
              parent.loc.start.line === parent.loc.end.line;
        }
 
        /**
         * Checks a node to see if it's followed by a semicolon.
         * @param {ASTNode} node The node to check.
         * @returns {void}
         */
        function checkForSemicolon(node) {
            const lastToken = sourceCode.getLastToken(node);
 
            if (never) {
                if (isUnnecessarySemicolon(lastToken)) {
                    report(node, true);
                }
            } else {
                if (!astUtils.isSemicolonToken(lastToken)) {
                    if (!exceptOneLine || !isOneLinerBlock(node)) {
                        report(node);
                    }
                } else {
                    if (exceptOneLine && isOneLinerBlock(node)) {
                        report(node, true);
                    }
                }
            }
        }
 
        /**
         * Checks to see if there's a semicolon after a variable declaration.
         * @param {ASTNode} node The node to check.
         * @returns {void}
         */
        function checkForSemicolonForVariableDeclaration(node) {
            const ancestors = context.getAncestors(),
                parentIndex = ancestors.length - 1,
                parent = ancestors[parentIndex];
 
            if ((parent.type !== "ForStatement" || parent.init !== node) &&
                (!/^For(?:In|Of)Statement/.test(parent.type) || parent.left !== node)
            ) {
                checkForSemicolon(node);
            }
        }
 
        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------
 
        return {
            VariableDeclaration: checkForSemicolonForVariableDeclaration,
            ExpressionStatement: checkForSemicolon,
            ReturnStatement: checkForSemicolon,
            ThrowStatement: checkForSemicolon,
            DoWhileStatement: checkForSemicolon,
            DebuggerStatement: checkForSemicolon,
            BreakStatement: checkForSemicolon,
            ContinueStatement: checkForSemicolon,
            ImportDeclaration: checkForSemicolon,
            ExportAllDeclaration: checkForSemicolon,
            ExportNamedDeclaration(node) {
                if (!node.declaration) {
                    checkForSemicolon(node);
                }
            },
            ExportDefaultDeclaration(node) {
                if (!/(?:Class|Function)Declaration/.test(node.declaration.type)) {
                    checkForSemicolon(node);
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/sort-imports.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/sort-imports.js

Statements: 8.16% (4 / 49)      Branches: 0% (0 / 47)      Functions: 0% (0 / 6)      Lines: 9.09% (4 / 44)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193                      1                                                                                                             1                                 1                 1                                                                                                                                                                                                        
/**
 * @fileoverview Rule to require sorting of import declarations
 * @author Christian Schuller
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce sorted import declarations within modules",
            category: "ECMAScript 6",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    ignoreCase: {
                        type: "boolean"
                    },
                    memberSyntaxSortOrder: {
                        type: "array",
                        items: {
                            enum: ["none", "all", "multiple", "single"]
                        },
                        uniqueItems: true,
                        minItems: 4,
                        maxItems: 4
                    },
                    ignoreMemberSort: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ],
 
        fixable: "code"
    },
 
    create(context) {
 
        const configuration = context.options[0] || {},
            ignoreCase = configuration.ignoreCase || false,
            ignoreMemberSort = configuration.ignoreMemberSort || false,
            memberSyntaxSortOrder = configuration.memberSyntaxSortOrder || ["none", "all", "multiple", "single"],
            sourceCode = context.getSourceCode();
        let previousDeclaration = null;
 
        /**
         * Gets the used member syntax style.
         *
         * import "my-module.js" --> none
         * import * as myModule from "my-module.js" --> all
         * import {myMember} from "my-module.js" --> single
         * import {foo, bar} from  "my-module.js" --> multiple
         *
         * @param {ASTNode} node - the ImportDeclaration node.
         * @returns {string} used member parameter style, ["all", "multiple", "single"]
         */
        function usedMemberSyntax(node) {
            if (node.specifiers.length === 0) {
                return "none";
            } else if (node.specifiers[0].type === "ImportNamespaceSpecifier") {
                return "all";
            } else if (node.specifiers.length === 1) {
                return "single";
            }
            return "multiple";
 
        }
 
        /**
         * Gets the group by member parameter index for given declaration.
         * @param {ASTNode} node - the ImportDeclaration node.
         * @returns {number} the declaration group by member index.
         */
        function getMemberParameterGroupIndex(node) {
            return memberSyntaxSortOrder.indexOf(usedMemberSyntax(node));
        }
 
        /**
         * Gets the local name of the first imported module.
         * @param {ASTNode} node - the ImportDeclaration node.
         * @returns {?string} the local name of the first imported module.
         */
        function getFirstLocalMemberName(node) {
            if (node.specifiers[0]) {
                return node.specifiers[0].local.name;
            }
            return null;
 
        }
 
        return {
            ImportDeclaration(node) {
                if (previousDeclaration) {
                    const currentMemberSyntaxGroupIndex = getMemberParameterGroupIndex(node),
                        previousMemberSyntaxGroupIndex = getMemberParameterGroupIndex(previousDeclaration);
                    let currentLocalMemberName = getFirstLocalMemberName(node),
                        previousLocalMemberName = getFirstLocalMemberName(previousDeclaration);
 
                    if (ignoreCase) {
                        previousLocalMemberName = previousLocalMemberName && previousLocalMemberName.toLowerCase();
                        currentLocalMemberName = currentLocalMemberName && currentLocalMemberName.toLowerCase();
                    }
 
                    // When the current declaration uses a different member syntax,
                    // then check if the ordering is correct.
                    // Otherwise, make a default string compare (like rule sort-vars to be consistent) of the first used local member name.
                    if (currentMemberSyntaxGroupIndex !== previousMemberSyntaxGroupIndex) {
                        if (currentMemberSyntaxGroupIndex < previousMemberSyntaxGroupIndex) {
                            context.report({
                                node,
                                message: "Expected '{{syntaxA}}' syntax before '{{syntaxB}}' syntax.",
                                data: {
                                    syntaxA: memberSyntaxSortOrder[currentMemberSyntaxGroupIndex],
                                    syntaxB: memberSyntaxSortOrder[previousMemberSyntaxGroupIndex]
                                }
                            });
                        }
                    } else {
                        if (previousLocalMemberName &&
                            currentLocalMemberName &&
                            currentLocalMemberName < previousLocalMemberName
                        ) {
                            context.report({
                                node,
                                message: "Imports should be sorted alphabetically."
                            });
                        }
                    }
                }
 
                if (!ignoreMemberSort) {
                    const importSpecifiers = node.specifiers.filter(specifier => specifier.type === "ImportSpecifier");
                    const getSortableName = ignoreCase ? specifier => specifier.local.name.toLowerCase() : specifier => specifier.local.name;
                    const firstUnsortedIndex = importSpecifiers.map(getSortableName).findIndex((name, index, array) => array[index - 1] > name);
 
                    if (firstUnsortedIndex !== -1) {
                        context.report({
                            node: importSpecifiers[firstUnsortedIndex],
                            message: "Member '{{memberName}}' of the import declaration should be sorted alphabetically.",
                            data: { memberName: importSpecifiers[firstUnsortedIndex].local.name },
                            fix(fixer) {
                                if (importSpecifiers.some(specifier => sourceCode.getComments(specifier).leading.length || sourceCode.getComments(specifier).trailing.length)) {
 
                                    // If there are comments in the ImportSpecifier list, don't rearrange the specifiers.
                                    return null;
                                }
 
                                return fixer.replaceTextRange(
                                    [importSpecifiers[0].range[0], importSpecifiers[importSpecifiers.length - 1].range[1]],
                                    importSpecifiers
 
                                        // Clone the importSpecifiers array to avoid mutating it
                                        .slice()
 
                                        // Sort the array into the desired order
                                        .sort((specifierA, specifierB) => {
                                            const aName = getSortableName(specifierA);
                                            const bName = getSortableName(specifierB);
 
                                            return aName > bName ? 1 : -1;
                                        })
 
                                        // Build a string out of the sorted list of import specifiers and the text between the originals
                                        .reduce((sourceText, specifier, index) => {
                                            const textAfterSpecifier = index === importSpecifiers.length - 1
                                                ? ""
                                                : sourceCode.getText().slice(importSpecifiers[index].range[1], importSpecifiers[index + 1].range[0]);
 
                                            return sourceText + sourceCode.getText(specifier) + textAfterSpecifier;
                                        }, "")
                                );
                            }
                        });
                    }
                }
 
                previousDeclaration = node;
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/sort-keys.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/sort-keys.js

Statements: 12.9% (4 / 31)      Branches: 0% (0 / 27)      Functions: 0% (0 / 13)      Lines: 12.9% (4 / 31)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159                      1                                     1                       1                                                             1                                                                                                                                                                          
/**
 * @fileoverview Rule to require object keys to be sorted
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils"),
    naturalCompare = require("natural-compare");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Gets the property name of the given `Property` node.
 *
 * - If the property's key is an `Identifier` node, this returns the key's name
 *   whether it's a computed property or not.
 * - If the property has a static name, this returns the static name.
 * - Otherwise, this returns null.
 *
 * @param {ASTNode} node - The `Property` node to get.
 * @returns {string|null} The property name or null.
 * @private
 */
function getPropertyName(node) {
    return astUtils.getStaticPropertyName(node) || node.key.name || null;
}
 
/**
 * Functions which check that the given 2 names are in specific order.
 *
 * Postfix `I` is meant insensitive.
 * Postfix `N` is meant natual.
 *
 * @private
 */
const isValidOrders = {
    asc(a, b) {
        return a <= b;
    },
    ascI(a, b) {
        return a.toLowerCase() <= b.toLowerCase();
    },
    ascN(a, b) {
        return naturalCompare(a, b) <= 0;
    },
    ascIN(a, b) {
        return naturalCompare(a.toLowerCase(), b.toLowerCase()) <= 0;
    },
    desc(a, b) {
        return isValidOrders.asc(b, a);
    },
    descI(a, b) {
        return isValidOrders.ascI(b, a);
    },
    descN(a, b) {
        return isValidOrders.ascN(b, a);
    },
    descIN(a, b) {
        return isValidOrders.ascIN(b, a);
    }
};
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require object keys to be sorted",
            category: "Stylistic Issues",
            recommended: false
        },
        schema: [
            {
                enum: ["asc", "desc"]
            },
            {
                type: "object",
                properties: {
                    caseSensitive: {
                        type: "boolean"
                    },
                    natural: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        // Parse options.
        const order = context.options[0] || "asc";
        const options = context.options[1];
        const insensitive = (options && options.caseSensitive) === false;
        const natual = Boolean(options && options.natural);
        const isValidOrder = isValidOrders[
            order + (insensitive ? "I" : "") + (natual ? "N" : "")
        ];
 
        // The stack to save the previous property's name for each object literals.
        let stack = null;
 
        return {
            ObjectExpression() {
                stack = {
                    upper: stack,
                    prevName: null
                };
            },
 
            "ObjectExpression:exit"() {
                stack = stack.upper;
            },
 
            Property(node) {
                if (node.parent.type === "ObjectPattern") {
                    return;
                }
 
                const prevName = stack.prevName;
                const thisName = getPropertyName(node);
 
                stack.prevName = thisName || prevName;
 
                if (!prevName || !thisName) {
                    return;
                }
 
                if (!isValidOrder(prevName, thisName)) {
                    context.report({
                        node,
                        loc: node.key.loc,
                        message: "Expected object keys to be in {{natual}}{{insensitive}}{{order}}ending order. '{{thisName}}' should be before '{{prevName}}'.",
                        data: {
                            thisName,
                            prevName,
                            order,
                            insensitive: insensitive ? "insensitive " : "",
                            natual: natual ? "natural " : ""
                        }
                    });
                }
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/sort-vars.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/sort-vars.js

Statements: 7.14% (1 / 14)      Branches: 0% (0 / 8)      Functions: 0% (0 / 2)      Lines: 7.69% (1 / 13)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63                      1                                                                                                      
/**
 * @fileoverview Rule to require sorting of variables within a single Variable Declaration block
 * @author Ilya Volodin
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require variables within the same declaration block to be sorted",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    ignoreCase: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        const configuration = context.options[0] || {},
            ignoreCase = configuration.ignoreCase || false;
 
        return {
            VariableDeclaration(node) {
                const idDeclarations = node.declarations.filter(decl => decl.id.type === "Identifier");
 
                idDeclarations.slice(1).reduce((memo, decl) => {
                    let lastVariableName = memo.id.name,
                        currenVariableName = decl.id.name;
 
                    if (ignoreCase) {
                        lastVariableName = lastVariableName.toLowerCase();
                        currenVariableName = currenVariableName.toLowerCase();
                    }
 
                    if (currenVariableName < lastVariableName) {
                        context.report({ node: decl, message: "Variables within the same declaration block should be sorted alphabetically." });
                        return memo;
                    }
                    return decl;
 
                }, idDeclarations[0]);
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/space-before-blocks.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/space-before-blocks.js

Statements: 12.5% (5 / 40)      Branches: 0% (0 / 26)      Functions: 0% (0 / 6)      Lines: 12.5% (5 / 40)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150              1           1                                                                                                                       1                 1                                                                                         1                                            
/**
 * @fileoverview A rule to ensure whitespace before blocks.
 * @author Mathias Schreck <https://github.com/lo1tuma>
 */
 
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent spacing before blocks",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                oneOf: [
                    {
                        enum: ["always", "never"]
                    },
                    {
                        type: "object",
                        properties: {
                            keywords: {
                                enum: ["always", "never"]
                            },
                            functions: {
                                enum: ["always", "never"]
                            },
                            classes: {
                                enum: ["always", "never"]
                            }
                        },
                        additionalProperties: false
                    }
                ]
            }
        ]
    },
 
    create(context) {
        const config = context.options[0],
            sourceCode = context.getSourceCode();
        let checkFunctions = true,
            checkKeywords = true,
            checkClasses = true;
 
        if (typeof config === "object") {
            checkFunctions = config.functions !== "never";
            checkKeywords = config.keywords !== "never";
            checkClasses = config.classes !== "never";
        } else if (config === "never") {
            checkFunctions = false;
            checkKeywords = false;
            checkClasses = false;
        }
 
        /**
         * Checks whether or not a given token is an arrow operator (=>) or a keyword
         * in order to avoid to conflict with `arrow-spacing` and `keyword-spacing`.
         *
         * @param {Token} token - A token to check.
         * @returns {boolean} `true` if the token is an arrow operator.
         */
        function isConflicted(token) {
            return (token.type === "Punctuator" && token.value === "=>") || token.type === "Keyword";
        }
 
        /**
         * Checks the given BlockStatement node has a preceding space if it doesn’t start on a new line.
         * @param {ASTNode|Token} node The AST node of a BlockStatement.
         * @returns {void} undefined.
         */
        function checkPrecedingSpace(node) {
            const precedingToken = sourceCode.getTokenBefore(node);
            let requireSpace;
 
            if (precedingToken && !isConflicted(precedingToken) && astUtils.isTokenOnSameLine(precedingToken, node)) {
                const hasSpace = sourceCode.isSpaceBetweenTokens(precedingToken, node);
                const parent = context.getAncestors().pop();
 
                if (parent.type === "FunctionExpression" || parent.type === "FunctionDeclaration") {
                    requireSpace = checkFunctions;
                } else if (node.type === "ClassBody") {
                    requireSpace = checkClasses;
                } else {
                    requireSpace = checkKeywords;
                }
 
                if (requireSpace) {
                    if (!hasSpace) {
                        context.report({
                            node,
                            message: "Missing space before opening brace.",
                            fix(fixer) {
                                return fixer.insertTextBefore(node, " ");
                            }
                        });
                    }
                } else {
                    if (hasSpace) {
                        context.report({
                            node,
                            message: "Unexpected space before opening brace.",
                            fix(fixer) {
                                return fixer.removeRange([precedingToken.range[1], node.range[0]]);
                            }
                        });
                    }
                }
            }
        }
 
        /**
         * Checks if the CaseBlock of an given SwitchStatement node has a preceding space.
         * @param {ASTNode} node The node of a SwitchStatement.
         * @returns {void} undefined.
         */
        function checkSpaceBeforeCaseBlock(node) {
            const cases = node.cases;
            let openingBrace;
 
            if (cases.length > 0) {
                openingBrace = sourceCode.getTokenBefore(cases[0]);
            } else {
                openingBrace = sourceCode.getLastToken(node, 1);
            }
 
            checkPrecedingSpace(openingBrace);
        }
 
        return {
            BlockStatement: checkPrecedingSpace,
            ClassBody: checkPrecedingSpace,
            SwitchStatement: checkSpaceBeforeCaseBlock
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/space-before-function-paren.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/space-before-function-paren.js

Statements: 15.15% (5 / 33)      Branches: 0% (0 / 37)      Functions: 0% (0 / 4)      Lines: 15.15% (5 / 33)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146                    1           1                                                                                           1                                           1                                                 1                                                                        
/**
 * @fileoverview Rule to validate spacing before function paren.
 * @author Mathias Schreck <https://github.com/lo1tuma>
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent spacing before `function` definition opening parenthesis",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                oneOf: [
                    {
                        enum: ["always", "never"]
                    },
                    {
                        type: "object",
                        properties: {
                            anonymous: {
                                enum: ["always", "never", "ignore"]
                            },
                            named: {
                                enum: ["always", "never", "ignore"]
                            },
                            asyncArrow: {
                                enum: ["always", "never", "ignore"]
                            }
                        },
                        additionalProperties: false
                    }
                ]
            }
        ]
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
        const baseConfig = typeof context.options[0] === "string" ? context.options[0] : "always";
        const overrideConfig = typeof context.options[0] === "object" ? context.options[0] : {};
 
        /**
         * Determines whether a function has a name.
         * @param {ASTNode} node The function node.
         * @returns {boolean} Whether the function has a name.
         */
        function isNamedFunction(node) {
            if (node.id) {
                return true;
            }
 
            const parent = node.parent;
 
            return parent.type === "MethodDefinition" ||
                (parent.type === "Property" &&
                    (
                        parent.kind === "get" ||
                        parent.kind === "set" ||
                        parent.method
                    )
                );
        }
 
        /**
         * Gets the config for a given function
         * @param {ASTNode} node The function node
         * @returns {string} "always", "never", or "ignore"
         */
        function getConfigForFunction(node) {
            if (node.type === "ArrowFunctionExpression") {
 
                // Always ignore non-async functions and arrow functions without parens, e.g. async foo => bar
                if (node.async && astUtils.isOpeningParenToken(sourceCode.getFirstToken(node, { skip: 1 }))) {
 
                    // For backwards compatibility, the base config does not apply to async arrow functions.
                    return overrideConfig.asyncArrow || "ignore";
                }
            } else if (isNamedFunction(node)) {
                return overrideConfig.named || baseConfig;
 
            // `generator-star-spacing` should warn anonymous generators. E.g. `function* () {}`
            } else if (!node.generator) {
                return overrideConfig.anonymous || baseConfig;
            }
 
            return "ignore";
        }
 
        /**
         * Checks the parens of a function node
         * @param {ASTNode} node A function node
         * @returns {void}
         */
        function checkFunction(node) {
            const functionConfig = getConfigForFunction(node);
 
            if (functionConfig === "ignore") {
                return;
            }
 
            const rightToken = sourceCode.getFirstToken(node, astUtils.isOpeningParenToken);
            const leftToken = sourceCode.getTokenBefore(rightToken);
            const hasSpacing = sourceCode.isSpaceBetweenTokens(leftToken, rightToken);
 
            if (hasSpacing && functionConfig === "never") {
                context.report({
                    node,
                    loc: leftToken.loc.end,
                    message: "Unexpected space before function parentheses.",
                    fix: fixer => fixer.removeRange([leftToken.range[1], rightToken.range[0]])
                });
            } else if (!hasSpacing && functionConfig === "always") {
                context.report({
                    node,
                    loc: leftToken.loc.end,
                    message: "Missing space before function parentheses.",
                    fix: fixer => fixer.insertTextAfter(leftToken, " ")
                });
            }
        }
 
        return {
            ArrowFunctionExpression: checkFunction,
            FunctionDeclaration: checkFunction,
            FunctionExpression: checkFunction
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/space-in-parens.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/space-in-parens.js

Statements: 10.59% (9 / 85)      Branches: 0% (0 / 64)      Functions: 0% (0 / 13)      Lines: 10.59% (9 / 85)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277            1           1                                                                                                         1                                                                               1                 1                   1                                         1                                           1                                                   1                                                                                                                                                                      
/**
 * @fileoverview Disallows or enforces spaces inside of parentheses.
 * @author Jonathan Rajavuori
 */
"use strict";
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent spacing inside parentheses",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                enum: ["always", "never"]
            },
            {
                type: "object",
                properties: {
                    exceptions: {
                        type: "array",
                        items: {
                            enum: ["{}", "[]", "()", "empty"]
                        },
                        uniqueItems: true
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        const MISSING_SPACE_MESSAGE = "There must be a space inside this paren.",
            REJECTED_SPACE_MESSAGE = "There should be no spaces inside this paren.",
            ALWAYS = context.options[0] === "always",
 
            exceptionsArrayOptions = (context.options.length === 2) ? context.options[1].exceptions : [],
            options = {};
        let exceptions;
 
        if (exceptionsArrayOptions.length) {
            options.braceException = exceptionsArrayOptions.indexOf("{}") !== -1;
            options.bracketException = exceptionsArrayOptions.indexOf("[]") !== -1;
            options.parenException = exceptionsArrayOptions.indexOf("()") !== -1;
            options.empty = exceptionsArrayOptions.indexOf("empty") !== -1;
        }
 
        /**
         * Produces an object with the opener and closer exception values
         * @param {Object} opts The exception options
         * @returns {Object} `openers` and `closers` exception values
         * @private
         */
        function getExceptions() {
            const openers = [],
                closers = [];
 
            if (options.braceException) {
                openers.push("{");
                closers.push("}");
            }
 
            if (options.bracketException) {
                openers.push("[");
                closers.push("]");
            }
 
            if (options.parenException) {
                openers.push("(");
                closers.push(")");
            }
 
            if (options.empty) {
                openers.push(")");
                closers.push("(");
            }
 
            return {
                openers,
                closers
            };
        }
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
        const sourceCode = context.getSourceCode();
 
        /**
         * Determines if a token is one of the exceptions for the opener paren
         * @param {Object} token The token to check
         * @returns {boolean} True if the token is one of the exceptions for the opener paren
         */
        function isOpenerException(token) {
            return token.type === "Punctuator" && exceptions.openers.indexOf(token.value) >= 0;
        }
 
        /**
         * Determines if a token is one of the exceptions for the closer paren
         * @param {Object} token The token to check
         * @returns {boolean} True if the token is one of the exceptions for the closer paren
         */
        function isCloserException(token) {
            return token.type === "Punctuator" && exceptions.closers.indexOf(token.value) >= 0;
        }
 
        /**
         * Determines if an opener paren should have a missing space after it
         * @param {Object} left The paren token
         * @param {Object} right The token after it
         * @returns {boolean} True if the paren should have a space
         */
        function shouldOpenerHaveSpace(left, right) {
            if (sourceCode.isSpaceBetweenTokens(left, right)) {
                return false;
            }
 
            if (ALWAYS) {
                if (astUtils.isClosingParenToken(right)) {
                    return false;
                }
                return !isOpenerException(right);
            }
            return isOpenerException(right);
 
        }
 
        /**
         * Determines if an closer paren should have a missing space after it
         * @param {Object} left The token before the paren
         * @param {Object} right The paren token
         * @returns {boolean} True if the paren should have a space
         */
        function shouldCloserHaveSpace(left, right) {
            if (astUtils.isOpeningParenToken(left)) {
                return false;
            }
 
            if (sourceCode.isSpaceBetweenTokens(left, right)) {
                return false;
            }
 
            if (ALWAYS) {
                return !isCloserException(left);
            }
            return isCloserException(left);
 
        }
 
        /**
         * Determines if an opener paren should not have an existing space after it
         * @param {Object} left The paren token
         * @param {Object} right The token after it
         * @returns {boolean} True if the paren should reject the space
         */
        function shouldOpenerRejectSpace(left, right) {
            if (right.type === "Line") {
                return false;
            }
 
            if (!astUtils.isTokenOnSameLine(left, right)) {
                return false;
            }
 
            if (!sourceCode.isSpaceBetweenTokens(left, right)) {
                return false;
            }
 
            if (ALWAYS) {
                return isOpenerException(right);
            }
            return !isOpenerException(right);
 
        }
 
        /**
         * Determines if an closer paren should not have an existing space after it
         * @param {Object} left The token before the paren
         * @param {Object} right The paren token
         * @returns {boolean} True if the paren should reject the space
         */
        function shouldCloserRejectSpace(left, right) {
            if (astUtils.isOpeningParenToken(left)) {
                return false;
            }
 
            if (!astUtils.isTokenOnSameLine(left, right)) {
                return false;
            }
 
            if (!sourceCode.isSpaceBetweenTokens(left, right)) {
                return false;
            }
 
            if (ALWAYS) {
                return isCloserException(left);
            }
            return !isCloserException(left);
 
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            Program: function checkParenSpaces(node) {
                exceptions = getExceptions();
                const tokens = sourceCode.tokensAndComments;
 
                tokens.forEach((token, i) => {
                    const prevToken = tokens[i - 1];
                    const nextToken = tokens[i + 1];
 
                    if (!astUtils.isOpeningParenToken(token) && !astUtils.isClosingParenToken(token)) {
                        return;
                    }
 
                    if (token.value === "(" && shouldOpenerHaveSpace(token, nextToken)) {
                        context.report({
                            node,
                            loc: token.loc.start,
                            message: MISSING_SPACE_MESSAGE,
                            fix(fixer) {
                                return fixer.insertTextAfter(token, " ");
                            }
                        });
                    } else if (token.value === "(" && shouldOpenerRejectSpace(token, nextToken)) {
                        context.report({
                            node,
                            loc: token.loc.start,
                            message: REJECTED_SPACE_MESSAGE,
                            fix(fixer) {
                                return fixer.removeRange([token.range[1], nextToken.range[0]]);
                            }
                        });
                    } else if (token.value === ")" && shouldCloserHaveSpace(prevToken, token)) {
 
                        // context.report(node, token.loc.start, MISSING_SPACE_MESSAGE);
                        context.report({
                            node,
                            loc: token.loc.start,
                            message: MISSING_SPACE_MESSAGE,
                            fix(fixer) {
                                return fixer.insertTextBefore(token, " ");
                            }
                        });
                    } else if (token.value === ")" && shouldCloserRejectSpace(prevToken, token)) {
                        context.report({
                            node,
                            loc: token.loc.start,
                            message: REJECTED_SPACE_MESSAGE,
                            fix(fixer) {
                                return fixer.removeRange([prevToken.range[1], token.range[0]]);
                            }
                        });
                    }
                });
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/space-infix-ops.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/space-infix-ops.js

Statements: 14.29% (6 / 42)      Branches: 0% (0 / 29)      Functions: 0% (0 / 7)      Lines: 14.29% (6 / 42)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167                    1                                                                                   1                                               1                                                             1                                       1                                 1                                            
/**
 * @fileoverview Require spaces around infix operators
 * @author Michael Ficarra
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require spacing around infix operators",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                type: "object",
                properties: {
                    int32Hint: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const int32Hint = context.options[0] ? context.options[0].int32Hint === true : false;
 
        const OPERATORS = [
            "*", "/", "%", "+", "-", "<<", ">>", ">>>", "<", "<=", ">", ">=", "in",
            "instanceof", "==", "!=", "===", "!==", "&", "^", "|", "&&", "||", "=",
            "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", "&=", "^=", "|=",
            "?", ":", ",", "**"
        ];
 
        const sourceCode = context.getSourceCode();
 
        /**
         * Returns the first token which violates the rule
         * @param {ASTNode} left - The left node of the main node
         * @param {ASTNode} right - The right node of the main node
         * @returns {Object} The violator token or null
         * @private
         */
        function getFirstNonSpacedToken(left, right) {
            const tokens = sourceCode.getTokensBetween(left, right, 1);
 
            for (let i = 1, l = tokens.length - 1; i < l; ++i) {
                const op = tokens[i];
 
                if (
                    (op.type === "Punctuator" || op.type === "Keyword") &&
                    OPERATORS.indexOf(op.value) >= 0 &&
                    (tokens[i - 1].range[1] >= op.range[0] || op.range[1] >= tokens[i + 1].range[0])
                ) {
                    return op;
                }
            }
            return null;
        }
 
        /**
         * Reports an AST node as a rule violation
         * @param {ASTNode} mainNode - The node to report
         * @param {Object} culpritToken - The token which has a problem
         * @returns {void}
         * @private
         */
        function report(mainNode, culpritToken) {
            context.report({
                node: mainNode,
                loc: culpritToken.loc.start,
                message: "Infix operators must be spaced.",
                fix(fixer) {
                    const previousToken = sourceCode.getTokenBefore(culpritToken);
                    const afterToken = sourceCode.getTokenAfter(culpritToken);
                    let fixString = "";
 
                    if (culpritToken.range[0] - previousToken.range[1] === 0) {
                        fixString = " ";
                    }
 
                    fixString += culpritToken.value;
 
                    if (afterToken.range[0] - culpritToken.range[1] === 0) {
                        fixString += " ";
                    }
 
                    return fixer.replaceText(culpritToken, fixString);
                }
            });
        }
 
        /**
         * Check if the node is binary then report
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function checkBinary(node) {
            if (node.left.typeAnnotation) {
                return;
            }
 
            const nonSpacedNode = getFirstNonSpacedToken(node.left, node.right);
 
            if (nonSpacedNode) {
                if (!(int32Hint && sourceCode.getText(node).substr(-2) === "|0")) {
                    report(node, nonSpacedNode);
                }
            }
        }
 
        /**
         * Check if the node is conditional
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function checkConditional(node) {
            const nonSpacedConsequesntNode = getFirstNonSpacedToken(node.test, node.consequent);
            const nonSpacedAlternateNode = getFirstNonSpacedToken(node.consequent, node.alternate);
 
            if (nonSpacedConsequesntNode) {
                report(node, nonSpacedConsequesntNode);
            } else if (nonSpacedAlternateNode) {
                report(node, nonSpacedAlternateNode);
            }
        }
 
        /**
         * Check if the node is a variable
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function checkVar(node) {
            if (node.init) {
                const nonSpacedNode = getFirstNonSpacedToken(node.id, node.init);
 
                if (nonSpacedNode) {
                    report(node, nonSpacedNode);
                }
            }
        }
 
        return {
            AssignmentExpression: checkBinary,
            AssignmentPattern: checkBinary,
            BinaryExpression: checkBinary,
            LogicalExpression: checkBinary,
            ConditionalExpression: checkConditional,
            VariableDeclarator: checkVar
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/space-unary-ops.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/space-unary-ops.js

Statements: 19.18% (14 / 73)      Branches: 0% (0 / 66)      Functions: 0% (0 / 20)      Lines: 19.18% (14 / 73)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330                    1                                                                                           1                   1                       1                         1                   1                       1                                             1                                                 1                                         1                               1                         1                                                                               1                                                                           1                                                                                
/**
 * @fileoverview This rule shoud require or disallow spaces before or after unary operations.
 * @author Marcin Kumorek
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent spacing before or after unary operators",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                type: "object",
                properties: {
                    words: {
                        type: "boolean"
                    },
                    nonwords: {
                        type: "boolean"
                    },
                    overrides: {
                        type: "object",
                        additionalProperties: {
                            type: "boolean"
                        }
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
        const options = context.options && Array.isArray(context.options) && context.options[0] || { words: true, nonwords: false };
 
        const sourceCode = context.getSourceCode();
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
        * Check if the node is the first "!" in a "!!" convert to Boolean expression
        * @param {ASTnode} node AST node
        * @returns {boolean} Whether or not the node is first "!" in "!!"
        */
        function isFirstBangInBangBangExpression(node) {
            return node && node.type === "UnaryExpression" && node.argument.operator === "!" &&
                node.argument && node.argument.type === "UnaryExpression" && node.argument.operator === "!";
        }
 
        /**
        * Check if the node's child argument is an "ObjectExpression"
        * @param {ASTnode} node AST node
        * @returns {boolean} Whether or not the argument's type is "ObjectExpression"
        */
        function isArgumentObjectExpression(node) {
            return node.argument && node.argument.type && node.argument.type === "ObjectExpression";
        }
 
        /**
         * Check if it is safe to remove the spaces between the two tokens in
         * the context of a non-word prefix unary operator. For example, `+ +1`
         * cannot safely be changed to `++1`.
         * @param {Token} firstToken The operator for a non-word prefix unary operator
         * @param {Token} secondToken The first token of its operand
         * @returns {boolean} Whether or not the spacing between the tokens can be removed
         */
        function canRemoveSpacesBetween(firstToken, secondToken) {
            return !(
                (firstToken.value === "+" && secondToken.value[0] === "+") ||
                (firstToken.value === "-" && secondToken.value[0] === "-")
            );
        }
 
        /**
        * Checks if an override exists for a given operator.
        * @param {ASTnode} node AST node
        * @param {string} operator Operator
        * @returns {boolean} Whether or not an override has been provided for the operator
        */
        function overrideExistsForOperator(node, operator) {
            return options.overrides && options.overrides.hasOwnProperty(operator);
        }
 
        /**
        * Gets the value that the override was set to for this operator
        * @param {ASTnode} node AST node
        * @param {string} operator Operator
        * @returns {boolean} Whether or not an override enforces a space with this operator
        */
        function overrideEnforcesSpaces(node, operator) {
            return options.overrides[operator];
        }
 
        /**
        * Verify Unary Word Operator has spaces after the word operator
        * @param {ASTnode} node AST node
        * @param {Object} firstToken first token from the AST node
        * @param {Object} secondToken second token from the AST node
        * @param {string} word The word to be used for reporting
        * @returns {void}
        */
        function verifyWordHasSpaces(node, firstToken, secondToken, word) {
            if (secondToken.range[0] === firstToken.range[1]) {
                context.report({
                    node,
                    message: "Unary word operator '{{word}}' must be followed by whitespace.",
                    data: {
                        word
                    },
                    fix(fixer) {
                        return fixer.insertTextAfter(firstToken, " ");
                    }
                });
            }
        }
 
        /**
        * Verify Unary Word Operator doesn't have spaces after the word operator
        * @param {ASTnode} node AST node
        * @param {Object} firstToken first token from the AST node
        * @param {Object} secondToken second token from the AST node
        * @param {string} word The word to be used for reporting
        * @returns {void}
        */
        function verifyWordDoesntHaveSpaces(node, firstToken, secondToken, word) {
            if (isArgumentObjectExpression(node)) {
                if (secondToken.range[0] > firstToken.range[1]) {
                    context.report({
                        node,
                        message: "Unexpected space after unary word operator '{{word}}'.",
                        data: {
                            word
                        },
                        fix(fixer) {
                            return fixer.removeRange([firstToken.range[1], secondToken.range[0]]);
                        }
                    });
                }
            }
        }
 
        /**
        * Check Unary Word Operators for spaces after the word operator
        * @param {ASTnode} node AST node
        * @param {Object} firstToken first token from the AST node
        * @param {Object} secondToken second token from the AST node
        * @param {string} word The word to be used for reporting
        * @returns {void}
        */
        function checkUnaryWordOperatorForSpaces(node, firstToken, secondToken, word) {
            word = word || firstToken.value;
 
            if (overrideExistsForOperator(node, word)) {
                if (overrideEnforcesSpaces(node, word)) {
                    verifyWordHasSpaces(node, firstToken, secondToken, word);
                } else {
                    verifyWordDoesntHaveSpaces(node, firstToken, secondToken, word);
                }
            } else if (options.words) {
                verifyWordHasSpaces(node, firstToken, secondToken, word);
            } else {
                verifyWordDoesntHaveSpaces(node, firstToken, secondToken, word);
            }
        }
 
        /**
        * Verifies YieldExpressions satisfy spacing requirements
        * @param {ASTnode} node AST node
        * @returns {void}
        */
        function checkForSpacesAfterYield(node) {
            const tokens = sourceCode.getFirstTokens(node, 3),
                word = "yield";
 
            if (!node.argument || node.delegate) {
                return;
            }
 
            checkUnaryWordOperatorForSpaces(node, tokens[0], tokens[1], word);
        }
 
        /**
        * Verifies AwaitExpressions satisfy spacing requirements
        * @param {ASTNode} node AwaitExpression AST node
        * @returns {void}
        */
        function checkForSpacesAfterAwait(node) {
            const tokens = sourceCode.getFirstTokens(node, 3);
 
            checkUnaryWordOperatorForSpaces(node, tokens[0], tokens[1], "await");
        }
 
        /**
        * Verifies UnaryExpression, UpdateExpression and NewExpression have spaces before or after the operator
        * @param {ASTnode} node AST node
        * @param {Object} firstToken First token in the expression
        * @param {Object} secondToken Second token in the expression
        * @returns {void}
        */
        function verifyNonWordsHaveSpaces(node, firstToken, secondToken) {
            if (node.prefix) {
                if (isFirstBangInBangBangExpression(node)) {
                    return;
                }
                if (firstToken.range[1] === secondToken.range[0]) {
                    context.report({
                        node,
                        message: "Unary operator '{{operator}}' must be followed by whitespace.",
                        data: {
                            operator: firstToken.value
                        },
                        fix(fixer) {
                            return fixer.insertTextAfter(firstToken, " ");
                        }
                    });
                }
            } else {
                if (firstToken.range[1] === secondToken.range[0]) {
                    context.report({
                        node,
                        message: "Space is required before unary expressions '{{token}}'.",
                        data: {
                            token: secondToken.value
                        },
                        fix(fixer) {
                            return fixer.insertTextBefore(secondToken, " ");
                        }
                    });
                }
            }
        }
 
        /**
        * Verifies UnaryExpression, UpdateExpression and NewExpression don't have spaces before or after the operator
        * @param {ASTnode} node AST node
        * @param {Object} firstToken First token in the expression
        * @param {Object} secondToken Second token in the expression
        * @returns {void}
        */
        function verifyNonWordsDontHaveSpaces(node, firstToken, secondToken) {
            if (node.prefix) {
                if (secondToken.range[0] > firstToken.range[1]) {
                    context.report({
                        node,
                        message: "Unexpected space after unary operator '{{operator}}'.",
                        data: {
                            operator: firstToken.value
                        },
                        fix(fixer) {
                            if (canRemoveSpacesBetween(firstToken, secondToken)) {
                                return fixer.removeRange([firstToken.range[1], secondToken.range[0]]);
                            }
                            return null;
                        }
                    });
                }
            } else {
                if (secondToken.range[0] > firstToken.range[1]) {
                    context.report({
                        node,
                        message: "Unexpected space before unary operator '{{operator}}'.",
                        data: {
                            operator: secondToken.value
                        },
                        fix(fixer) {
                            return fixer.removeRange([firstToken.range[1], secondToken.range[0]]);
                        }
                    });
                }
            }
        }
 
        /**
        * Verifies UnaryExpression, UpdateExpression and NewExpression satisfy spacing requirements
        * @param {ASTnode} node AST node
        * @returns {void}
        */
        function checkForSpaces(node) {
            const tokens = sourceCode.getFirstTokens(node, 2),
                firstToken = tokens[0],
                secondToken = tokens[1];
 
            if ((node.type === "NewExpression" || node.prefix) && firstToken.type === "Keyword") {
                checkUnaryWordOperatorForSpaces(node, firstToken, secondToken);
                return;
            }
 
            const operator = node.prefix ? tokens[0].value : tokens[1].value;
 
            if (overrideExistsForOperator(node, operator)) {
                if (overrideEnforcesSpaces(node, operator)) {
                    verifyNonWordsHaveSpaces(node, firstToken, secondToken);
                } else {
                    verifyNonWordsDontHaveSpaces(node, firstToken, secondToken);
                }
            } else if (options.nonwords) {
                verifyNonWordsHaveSpaces(node, firstToken, secondToken);
            } else {
                verifyNonWordsDontHaveSpaces(node, firstToken, secondToken);
            }
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            UnaryExpression: checkForSpaces,
            UpdateExpression: checkForSpaces,
            NewExpression: checkForSpaces,
            YieldExpression: checkForSpacesAfterYield,
            AwaitExpression: checkForSpacesAfterAwait
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/spaced-comment.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/spaced-comment.js

Statements: 13.79% (12 / 87)      Branches: 0% (0 / 65)      Functions: 0% (0 / 12)      Lines: 13.79% (12 / 87)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374            1 1                     1                         1                   1                                       1                                                                                             1                                                                         1                   1                                                                                                                                                                                                                             1                                                               1                                           1                                                                                                          
/**
 * @fileoverview Source code for spaced-comments rule
 * @author Gyandeep Singh
 */
"use strict";
 
const lodash = require("lodash");
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Escapes the control characters of a given string.
 * @param {string} s - A string to escape.
 * @returns {string} An escaped string.
 */
function escape(s) {
    const isOneChar = s.length === 1;
 
    s = lodash.escapeRegExp(s);
    return isOneChar ? s : `(?:${s})`;
}
 
/**
 * Escapes the control characters of a given string.
 * And adds a repeat flag.
 * @param {string} s - A string to escape.
 * @returns {string} An escaped string.
 */
function escapeAndRepeat(s) {
    return `${escape(s)}+`;
}
 
/**
 * Parses `markers` option.
 * If markers don't include `"*"`, this adds `"*"` to allow JSDoc comments.
 * @param {string[]} [markers] - A marker list.
 * @returns {string[]} A marker list.
 */
function parseMarkersOption(markers) {
    markers = markers ? markers.slice(0) : [];
 
    // `*` is a marker for JSDoc comments.
    if (markers.indexOf("*") === -1) {
        markers.push("*");
    }
 
    return markers;
}
 
/**
 * Creates string pattern for exceptions.
 * Generated pattern:
 *
 * 1. A space or an exception pattern sequence.
 *
 * @param {string[]} exceptions - An exception pattern list.
 * @returns {string} A regular expression string for exceptions.
 */
function createExceptionsPattern(exceptions) {
    let pattern = "";
 
    /*
     * A space or an exception pattern sequence.
     * []                 ==> "\s"
     * ["-"]              ==> "(?:\s|\-+$)"
     * ["-", "="]         ==> "(?:\s|(?:\-+|=+)$)"
     * ["-", "=", "--=="] ==> "(?:\s|(?:\-+|=+|(?:\-\-==)+)$)" ==> https://jex.im/regulex/#!embed=false&flags=&re=(%3F%3A%5Cs%7C(%3F%3A%5C-%2B%7C%3D%2B%7C(%3F%3A%5C-%5C-%3D%3D)%2B)%24)
     */
    if (exceptions.length === 0) {
 
        // a space.
        pattern += "\\s";
    } else {
 
        // a space or...
        pattern += "(?:\\s|";
 
        if (exceptions.length === 1) {
 
            // a sequence of the exception pattern.
            pattern += escapeAndRepeat(exceptions[0]);
        } else {
 
            // a sequence of one of the exception patterns.
            pattern += "(?:";
            pattern += exceptions.map(escapeAndRepeat).join("|");
            pattern += ")";
        }
        pattern += `(?:$|[${Array.from(astUtils.LINEBREAKS).join("")}]))`;
    }
 
    return pattern;
}
 
/**
 * Creates RegExp object for `always` mode.
 * Generated pattern for beginning of comment:
 *
 * 1. First, a marker or nothing.
 * 2. Next, a space or an exception pattern sequence.
 *
 * @param {string[]} markers - A marker list.
 * @param {string[]} exceptions - An exception pattern list.
 * @returns {RegExp} A RegExp object for the beginning of a comment in `always` mode.
 */
function createAlwaysStylePattern(markers, exceptions) {
    let pattern = "^";
 
    /*
     * A marker or nothing.
     * ["*"]            ==> "\*?"
     * ["*", "!"]       ==> "(?:\*|!)?"
     * ["*", "/", "!<"] ==> "(?:\*|\/|(?:!<))?" ==> https://jex.im/regulex/#!embed=false&flags=&re=(%3F%3A%5C*%7C%5C%2F%7C(%3F%3A!%3C))%3F
     */
    if (markers.length === 1) {
 
        // the marker.
        pattern += escape(markers[0]);
    } else {
 
        // one of markers.
        pattern += "(?:";
        pattern += markers.map(escape).join("|");
        pattern += ")";
    }
 
    pattern += "?"; // or nothing.
    pattern += createExceptionsPattern(exceptions);
 
    return new RegExp(pattern);
}
 
/**
 * Creates RegExp object for `never` mode.
 * Generated pattern for beginning of comment:
 *
 * 1. First, a marker or nothing (captured).
 * 2. Next, a space or a tab.
 *
 * @param {string[]} markers - A marker list.
 * @returns {RegExp} A RegExp object for `never` mode.
 */
function createNeverStylePattern(markers) {
    const pattern = `^(${markers.map(escape).join("|")})?[ \t]+`;
 
    return new RegExp(pattern);
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce consistent spacing after the `//` or `/*` in a comment",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                enum: ["always", "never"]
            },
            {
                type: "object",
                properties: {
                    exceptions: {
                        type: "array",
                        items: {
                            type: "string"
                        }
                    },
                    markers: {
                        type: "array",
                        items: {
                            type: "string"
                        }
                    },
                    line: {
                        type: "object",
                        properties: {
                            exceptions: {
                                type: "array",
                                items: {
                                    type: "string"
                                }
                            },
                            markers: {
                                type: "array",
                                items: {
                                    type: "string"
                                }
                            }
                        },
                        additionalProperties: false
                    },
                    block: {
                        type: "object",
                        properties: {
                            exceptions: {
                                type: "array",
                                items: {
                                    type: "string"
                                }
                            },
                            markers: {
                                type: "array",
                                items: {
                                    type: "string"
                                }
                            },
                            balanced: {
                                type: "boolean"
                            }
                        },
                        additionalProperties: false
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        // Unless the first option is never, require a space
        const requireSpace = context.options[0] !== "never";
 
        /*
         * Parse the second options.
         * If markers don't include `"*"`, it's added automatically for JSDoc
         * comments.
         */
        const config = context.options[1] || {};
        const balanced = config.block && config.block.balanced;
 
        const styleRules = ["block", "line"].reduce((rule, type) => {
            const markers = parseMarkersOption(config[type] && config[type].markers || config.markers);
            const exceptions = config[type] && config[type].exceptions || config.exceptions || [];
            const endNeverPattern = "[ \t]+$";
 
            // Create RegExp object for valid patterns.
            rule[type] = {
                beginRegex: requireSpace ? createAlwaysStylePattern(markers, exceptions) : createNeverStylePattern(markers),
                endRegex: balanced && requireSpace ? new RegExp(`${createExceptionsPattern(exceptions)}$`) : new RegExp(endNeverPattern),
                hasExceptions: exceptions.length > 0,
                markers: new RegExp(`^(${markers.map(escape).join("|")})`)
            };
 
            return rule;
        }, {});
 
        /**
         * Reports a beginning spacing error with an appropriate message.
         * @param {ASTNode} node - A comment node to check.
         * @param {string} message - An error message to report.
         * @param {Array} match - An array of match results for markers.
         * @param {string} refChar - Character used for reference in the error message.
         * @returns {void}
         */
        function reportBegin(node, message, match, refChar) {
            const type = node.type.toLowerCase(),
                commentIdentifier = type === "block" ? "/*" : "//";
 
            context.report({
                node,
                fix(fixer) {
                    const start = node.range[0];
                    let end = start + 2;
 
                    if (requireSpace) {
                        if (match) {
                            end += match[0].length;
                        }
                        return fixer.insertTextAfterRange([start, end], " ");
                    }
                    end += match[0].length;
                    return fixer.replaceTextRange([start, end], commentIdentifier + (match[1] ? match[1] : ""));
 
                },
                message,
                data: { refChar }
            });
        }
 
        /**
         * Reports an ending spacing error with an appropriate message.
         * @param {ASTNode} node - A comment node to check.
         * @param {string} message - An error message to report.
         * @param {string} match - An array of the matched whitespace characters.
         * @returns {void}
         */
        function reportEnd(node, message, match) {
            context.report({
                node,
                fix(fixer) {
                    if (requireSpace) {
                        return fixer.insertTextAfterRange([node.start, node.end - 2], " ");
                    }
                    const end = node.end - 2,
                        start = end - match[0].length;
 
                    return fixer.replaceTextRange([start, end], "");
 
                },
                message
            });
        }
 
        /**
         * Reports a given comment if it's invalid.
         * @param {ASTNode} node - a comment node to check.
         * @returns {void}
         */
        function checkCommentForSpace(node) {
            const type = node.type.toLowerCase(),
                rule = styleRules[type],
                commentIdentifier = type === "block" ? "/*" : "//";
 
            // Ignores empty comments.
            if (node.value.length === 0) {
                return;
            }
 
            const beginMatch = rule.beginRegex.exec(node.value);
            const endMatch = rule.endRegex.exec(node.value);
 
            // Checks.
            if (requireSpace) {
                if (!beginMatch) {
                    const hasMarker = rule.markers.exec(node.value);
                    const marker = hasMarker ? commentIdentifier + hasMarker[0] : commentIdentifier;
 
                    if (rule.hasExceptions) {
                        reportBegin(node, "Expected exception block, space or tab after '{{refChar}}' in comment.", hasMarker, marker);
                    } else {
                        reportBegin(node, "Expected space or tab after '{{refChar}}' in comment.", hasMarker, marker);
                    }
                }
 
                if (balanced && type === "block" && !endMatch) {
                    reportEnd(node, "Expected space or tab before '*/' in comment.");
                }
            } else {
                if (beginMatch) {
                    if (!beginMatch[1]) {
                        reportBegin(node, "Unexpected space or tab after '{{refChar}}' in comment.", beginMatch, commentIdentifier);
                    } else {
                        reportBegin(node, "Unexpected space or tab after marker ({{refChar}}) in comment.", beginMatch, beginMatch[1]);
                    }
                }
 
                if (balanced && type === "block" && endMatch) {
                    reportEnd(node, "Unexpected space or tab before '*/' in comment.", endMatch);
                }
            }
        }
 
        return {
 
            LineComment: checkCommentForSpace,
            BlockComment: checkCommentForSpace
 
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/strict.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/strict.js

Statements: 19.18% (14 / 73)      Branches: 0% (0 / 58)      Functions: 0% (0 / 15)      Lines: 19.44% (14 / 72)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279                      1           1                                     1                                                   1                   1               1                                                                     1                 1                         1                         1                     1                     1                                                                     1                     1                                                                                                                        
/**
 * @fileoverview Rule to control usage of strict mode directives.
 * @author Brandon Mills
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const messages = {
    function: "Use the function form of 'use strict'.",
    global: "Use the global form of 'use strict'.",
    multiple: "Multiple 'use strict' directives.",
    never: "Strict mode is not permitted.",
    unnecessary: "Unnecessary 'use strict' directive.",
    module: "'use strict' is unnecessary inside of modules.",
    implied: "'use strict' is unnecessary when implied strict mode is enabled.",
    unnecessaryInClasses: "'use strict' is unnecessary inside of classes.",
    nonSimpleParameterList: "'use strict' directive inside a function with non-simple parameter list throws a syntax error since ES2016.",
    wrap: "Wrap {{name}} in a function with 'use strict' directive."
};
 
/**
 * Gets all of the Use Strict Directives in the Directive Prologue of a group of
 * statements.
 * @param {ASTNode[]} statements Statements in the program or function body.
 * @returns {ASTNode[]} All of the Use Strict Directives.
 */
function getUseStrictDirectives(statements) {
    const directives = [];
 
    for (let i = 0; i < statements.length; i++) {
        const statement = statements[i];
 
        if (
            statement.type === "ExpressionStatement" &&
            statement.expression.type === "Literal" &&
            statement.expression.value === "use strict"
        ) {
            directives[i] = statement;
        } else {
            break;
        }
    }
 
    return directives;
}
 
/**
 * Checks whether a given parameter is a simple parameter.
 *
 * @param {ASTNode} node - A pattern node to check.
 * @returns {boolean} `true` if the node is an Identifier node.
 */
function isSimpleParameter(node) {
    return node.type === "Identifier";
}
 
/**
 * Checks whether a given parameter list is a simple parameter list.
 *
 * @param {ASTNode[]} params - A parameter list to check.
 * @returns {boolean} `true` if the every parameter is an Identifier node.
 */
function isSimpleParameterList(params) {
    return params.every(isSimpleParameter);
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require or disallow strict mode directives",
            category: "Strict Mode",
            recommended: false
        },
 
        schema: [
            {
                enum: ["never", "global", "function", "safe"]
            }
        ],
 
        fixable: "code"
    },
 
    create(context) {
 
        const ecmaFeatures = context.parserOptions.ecmaFeatures || {},
            scopes = [],
            classScopes = [];
        let mode = context.options[0] || "safe";
 
        if (ecmaFeatures.impliedStrict) {
            mode = "implied";
        } else if (mode === "safe") {
            mode = ecmaFeatures.globalReturn ? "global" : "function";
        }
 
        /**
        * Determines whether a reported error should be fixed, depending on the error type.
        * @param {string} errorType The type of error
        * @returns {boolean} `true` if the reported error should be fixed
        */
        function shouldFix(errorType) {
            return errorType === "multiple" || errorType === "unnecessary" || errorType === "module" || errorType === "implied" || errorType === "unnecessaryInClasses";
        }
 
        /**
        * Gets a fixer function to remove a given 'use strict' directive.
        * @param {ASTNode} node The directive that should be removed
        * @returns {Function} A fixer function
        */
        function getFixFunction(node) {
            return fixer => fixer.remove(node);
        }
 
        /**
         * Report a slice of an array of nodes with a given message.
         * @param {ASTNode[]} nodes Nodes.
         * @param {string} start Index to start from.
         * @param {string} end Index to end before.
         * @param {string} message Message to display.
         * @param {boolean} fix `true` if the directive should be fixed (i.e. removed)
         * @returns {void}
         */
        function reportSlice(nodes, start, end, message, fix) {
            nodes.slice(start, end).forEach(node => {
                context.report({ node, message, fix: fix ? getFixFunction(node) : null });
            });
        }
 
        /**
         * Report all nodes in an array with a given message.
         * @param {ASTNode[]} nodes Nodes.
         * @param {string} message Message to display.
         * @param {boolean} fix `true` if the directive should be fixed (i.e. removed)
         * @returns {void}
         */
        function reportAll(nodes, message, fix) {
            reportSlice(nodes, 0, nodes.length, message, fix);
        }
 
        /**
         * Report all nodes in an array, except the first, with a given message.
         * @param {ASTNode[]} nodes Nodes.
         * @param {string} message Message to display.
         * @param {boolean} fix `true` if the directive should be fixed (i.e. removed)
         * @returns {void}
         */
        function reportAllExceptFirst(nodes, message, fix) {
            reportSlice(nodes, 1, nodes.length, message, fix);
        }
 
        /**
         * Entering a function in 'function' mode pushes a new nested scope onto the
         * stack. The new scope is true if the nested function is strict mode code.
         * @param {ASTNode} node The function declaration or expression.
         * @param {ASTNode[]} useStrictDirectives The Use Strict Directives of the node.
         * @returns {void}
         */
        function enterFunctionInFunctionMode(node, useStrictDirectives) {
            const isInClass = classScopes.length > 0,
                isParentGlobal = scopes.length === 0 && classScopes.length === 0,
                isParentStrict = scopes.length > 0 && scopes[scopes.length - 1],
                isStrict = useStrictDirectives.length > 0;
 
            if (isStrict) {
                if (!isSimpleParameterList(node.params)) {
                    context.report({ node: useStrictDirectives[0], message: messages.nonSimpleParameterList });
                } else if (isParentStrict) {
                    context.report({ node: useStrictDirectives[0], message: messages.unnecessary, fix: getFixFunction(useStrictDirectives[0]) });
                } else if (isInClass) {
                    context.report({ node: useStrictDirectives[0], message: messages.unnecessaryInClasses, fix: getFixFunction(useStrictDirectives[0]) });
                }
 
                reportAllExceptFirst(useStrictDirectives, messages.multiple, true);
            } else if (isParentGlobal) {
                if (isSimpleParameterList(node.params)) {
                    context.report({ node, message: messages.function });
                } else {
                    context.report({
                        node,
                        message: messages.wrap,
                        data: { name: astUtils.getFunctionNameWithKind(node) }
                    });
                }
            }
 
            scopes.push(isParentStrict || isStrict);
        }
 
        /**
         * Exiting a function in 'function' mode pops its scope off the stack.
         * @returns {void}
         */
        function exitFunctionInFunctionMode() {
            scopes.pop();
        }
 
        /**
         * Enter a function and either:
         * - Push a new nested scope onto the stack (in 'function' mode).
         * - Report all the Use Strict Directives (in the other modes).
         * @param {ASTNode} node The function declaration or expression.
         * @returns {void}
         */
        function enterFunction(node) {
            const isBlock = node.body.type === "BlockStatement",
                useStrictDirectives = isBlock
                    ? getUseStrictDirectives(node.body.body) : [];
 
            if (mode === "function") {
                enterFunctionInFunctionMode(node, useStrictDirectives);
            } else if (useStrictDirectives.length > 0) {
                if (isSimpleParameterList(node.params)) {
                    reportAll(useStrictDirectives, messages[mode], shouldFix(mode));
                } else {
                    context.report({ node: useStrictDirectives[0], message: messages.nonSimpleParameterList });
                    reportAllExceptFirst(useStrictDirectives, messages.multiple, true);
                }
            }
        }
 
        const rule = {
            Program(node) {
                const useStrictDirectives = getUseStrictDirectives(node.body);
 
                if (node.sourceType === "module") {
                    mode = "module";
                }
 
                if (mode === "global") {
                    if (node.body.length > 0 && useStrictDirectives.length === 0) {
                        context.report({ node, message: messages.global });
                    }
                    reportAllExceptFirst(useStrictDirectives, messages.multiple, true);
                } else {
                    reportAll(useStrictDirectives, messages[mode], shouldFix(mode));
                }
            },
            FunctionDeclaration: enterFunction,
            FunctionExpression: enterFunction,
            ArrowFunctionExpression: enterFunction
        };
 
        if (mode === "function") {
            Object.assign(rule, {
 
                // Inside of class bodies are always strict mode.
                ClassBody() {
                    classScopes.push(true);
                },
                "ClassBody:exit"() {
                    classScopes.pop();
                },
 
                "FunctionDeclaration:exit": exitFunctionInFunctionMode,
                "FunctionExpression:exit": exitFunctionInFunctionMode,
                "ArrowFunctionExpression:exit": exitFunctionInFunctionMode
            });
        }
 
        return rule;
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/symbol-description.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/symbol-description.js

Statements: 23.08% (3 / 13)      Branches: 0% (0 / 8)      Functions: 0% (0 / 3)      Lines: 23.08% (3 / 13)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68                      1             1                                       1                                                          
/**
 * @fileoverview Rule to enforce description with the `Symbol` object
 * @author Jarek Rencz
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
 
module.exports = {
    meta: {
        docs: {
            description: "require symbol descriptions",
            category: "ECMAScript 6",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
 
        /**
         * Reports if node does not conform the rule in case rule is set to
         * report missing description
         *
         * @param {ASTNode} node - A CallExpression node to check.
         * @returns {void}
         */
        function checkArgument(node) {
            if (node.arguments.length === 0) {
                context.report({
                    node,
                    message: "Expected Symbol to have a description."
                });
            }
        }
 
        return {
            "Program:exit"() {
                const scope = context.getScope();
                const variable = astUtils.getVariableByName(scope, "Symbol");
 
                if (variable && variable.defs.length === 0) {
                    variable.references.forEach(reference => {
                        const node = reference.identifier;
 
                        if (astUtils.isCallee(node)) {
                            checkArgument(node.parent);
                        }
                    });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/template-curly-spacing.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/template-curly-spacing.js

Statements: 24% (6 / 25)      Branches: 0% (0 / 18)      Functions: 0% (0 / 6)      Lines: 24% (6 / 25)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123                      1           1 1           1                                                 1                                                               1                                                                                  
/**
 * @fileoverview Rule to enforce spacing around embedded expressions of template strings
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const OPEN_PAREN = /\$\{$/;
const CLOSE_PAREN = /^\}/;
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require or disallow spacing around embedded expressions of template strings",
            category: "ECMAScript 6",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            { enum: ["always", "never"] }
        ]
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
        const always = context.options[0] === "always";
        const prefix = always ? "Expected" : "Unexpected";
 
        /**
         * Checks spacing before `}` of a given token.
         * @param {Token} token - A token to check. This is a Template token.
         * @returns {void}
         */
        function checkSpacingBefore(token) {
            const prevToken = sourceCode.getTokenBefore(token);
 
            if (prevToken &&
                CLOSE_PAREN.test(token.value) &&
                astUtils.isTokenOnSameLine(prevToken, token) &&
                sourceCode.isSpaceBetweenTokens(prevToken, token) !== always
            ) {
                context.report({
                    loc: token.loc.start,
                    message: "{{prefix}} space(s) before '}'.",
                    data: {
                        prefix
                    },
                    fix(fixer) {
                        if (always) {
                            return fixer.insertTextBefore(token, " ");
                        }
                        return fixer.removeRange([
                            prevToken.range[1],
                            token.range[0]
                        ]);
                    }
                });
            }
        }
 
        /**
         * Checks spacing after `${` of a given token.
         * @param {Token} token - A token to check. This is a Template token.
         * @returns {void}
         */
        function checkSpacingAfter(token) {
            const nextToken = sourceCode.getTokenAfter(token);
 
            if (nextToken &&
                OPEN_PAREN.test(token.value) &&
                astUtils.isTokenOnSameLine(token, nextToken) &&
                sourceCode.isSpaceBetweenTokens(token, nextToken) !== always
            ) {
                context.report({
                    loc: {
                        line: token.loc.end.line,
                        column: token.loc.end.column - 2
                    },
                    message: "{{prefix}} space(s) after '${'.",
                    data: {
                        prefix
                    },
                    fix(fixer) {
                        if (always) {
                            return fixer.insertTextAfter(token, " ");
                        }
                        return fixer.removeRange([
                            token.range[1],
                            nextToken.range[0]
                        ]);
                    }
                });
            }
        }
 
        return {
            TemplateElement(node) {
                const token = sourceCode.getFirstToken(node);
 
                checkSpacingBefore(token);
                checkSpacingAfter(token);
            }
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/template-tag-spacing.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/template-tag-spacing.js

Statements: 10.53% (2 / 19)      Branches: 0% (0 / 10)      Functions: 0% (0 / 4)      Lines: 11.11% (2 / 18)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79                      1                                                 1                                                                                    
/**
 * @fileoverview Rule to check spacing between template tags and their literals
 * @author Jonathan Wilsson
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require or disallow spacing between template tags and their literals",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            { enum: ["always", "never"] }
        ]
    },
 
    create(context) {
        const never = context.options[0] !== "always";
        const sourceCode = context.getSourceCode();
 
        /**
         * Check if a space is present between a template tag and its literal
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function checkSpacing(node) {
            const tagToken = sourceCode.getTokenBefore(node.quasi);
            const literalToken = sourceCode.getFirstToken(node.quasi);
            const hasWhitespace = sourceCode.isSpaceBetweenTokens(tagToken, literalToken);
 
            if (never && hasWhitespace) {
                context.report({
                    node,
                    loc: tagToken.loc.start,
                    message: "Unexpected space between template tag and template literal.",
                    fix(fixer) {
                        const comments = sourceCode.getComments(node.quasi).leading;
 
                        // Don't fix anything if there's a single line comment after the template tag
                        if (comments.some(comment => comment.type === "Line")) {
                            return null;
                        }
 
                        return fixer.replaceTextRange(
                            [tagToken.range[1], literalToken.range[0]],
                            comments.reduce((text, comment) => text + sourceCode.getText(comment), "")
                        );
                    }
                });
            } else if (!never && !hasWhitespace) {
                context.report({
                    node,
                    loc: tagToken.loc.start,
                    message: "Missing space between template tag and template literal.",
                    fix(fixer) {
                        return fixer.insertTextAfter(tagToken, " ");
                    }
                });
            }
        }
 
        return {
            TaggedTemplateExpression: checkSpacing
        };
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/unicode-bom.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/unicode-bom.js

Statements: 11.11% (1 / 9)      Branches: 0% (0 / 10)      Functions: 0% (0 / 4)      Lines: 11.11% (1 / 9)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68                    1                                                                                                                  
/**
 * @fileoverview Require or disallow Unicode BOM
 * @author Andrew Johnston <https://github.com/ehjay>
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require or disallow Unicode byte order mark (BOM)",
            category: "Stylistic Issues",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                enum: ["always", "never"]
            }
        ]
    },
 
    create(context) {
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
 
            Program: function checkUnicodeBOM(node) {
 
                const sourceCode = context.getSourceCode(),
                    location = { column: 0, line: 1 },
                    requireBOM = context.options[0] || "never";
 
                if (!sourceCode.hasBOM && (requireBOM === "always")) {
                    context.report({
                        node,
                        loc: location,
                        message: "Expected Unicode BOM (Byte Order Mark).",
                        fix(fixer) {
                            return fixer.insertTextBeforeRange([0, 1], "\uFEFF");
                        }
                    });
                } else if (sourceCode.hasBOM && (requireBOM === "never")) {
                    context.report({
                        node,
                        loc: location,
                        message: "Unexpected Unicode BOM (Byte Order Mark).",
                        fix(fixer) {
                            return fixer.removeRange([-1, 0]);
                        }
                    });
                }
            }
 
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/use-isnan.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/use-isnan.js

Statements: 25% (1 / 4)      Branches: 0% (0 / 5)      Functions: 0% (0 / 2)      Lines: 25% (1 / 4)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36                      1                                                
/**
 * @fileoverview Rule to flag comparisons to the value NaN
 * @author James Allardice
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require calls to `isNaN()` when checking for `NaN`",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: []
    },
 
    create(context) {
 
        return {
            BinaryExpression(node) {
                if (/^(?:[<>]|[!=]=)=?$/.test(node.operator) && (node.left.name === "NaN" || node.right.name === "NaN")) {
                    context.report({ node, message: "Use the isNaN function to compare with NaN." });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/valid-jsdoc.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/valid-jsdoc.js

Statements: 9.52% (10 / 105)      Branches: 0% (0 / 131)      Functions: 0% (0 / 9)      Lines: 9.52% (10 / 105)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411                    1           1                                                                                                                                               1                   1                         1                           1                   1                           1                                               1                                                                                                       1                                                                                                                                                                                                                                                                                                                                                                                  
/**
 * @fileoverview Validates JSDoc comments are syntactically correct
 * @author Nicholas C. Zakas
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const doctrine = require("doctrine");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce valid JSDoc comments",
            category: "Possible Errors",
            recommended: false
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    prefer: {
                        type: "object",
                        additionalProperties: {
                            type: "string"
                        }
                    },
                    preferType: {
                        type: "object",
                        additionalProperties: {
                            type: "string"
                        }
                    },
                    requireReturn: {
                        type: "boolean"
                    },
                    requireParamDescription: {
                        type: "boolean"
                    },
                    requireReturnDescription: {
                        type: "boolean"
                    },
                    matchDescription: {
                        type: "string"
                    },
                    requireReturnType: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        const options = context.options[0] || {},
            prefer = options.prefer || {},
            sourceCode = context.getSourceCode(),
 
            // these both default to true, so you have to explicitly make them false
            requireReturn = options.requireReturn !== false,
            requireParamDescription = options.requireParamDescription !== false,
            requireReturnDescription = options.requireReturnDescription !== false,
            requireReturnType = options.requireReturnType !== false,
            preferType = options.preferType || {},
            checkPreferType = Object.keys(preferType).length !== 0;
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        // Using a stack to store if a function returns or not (handling nested functions)
        const fns = [];
 
        /**
         * Check if node type is a Class
         * @param {ASTNode} node node to check.
         * @returns {boolean} True is its a class
         * @private
         */
        function isTypeClass(node) {
            return node.type === "ClassExpression" || node.type === "ClassDeclaration";
        }
 
        /**
         * When parsing a new function, store it in our function stack.
         * @param {ASTNode} node A function node to check.
         * @returns {void}
         * @private
         */
        function startFunction(node) {
            fns.push({
                returnPresent: (node.type === "ArrowFunctionExpression" && node.body.type !== "BlockStatement") ||
                    isTypeClass(node)
            });
        }
 
        /**
         * Indicate that return has been found in the current function.
         * @param {ASTNode} node The return node.
         * @returns {void}
         * @private
         */
        function addReturn(node) {
            const functionState = fns[fns.length - 1];
 
            if (functionState && node.argument !== null) {
                functionState.returnPresent = true;
            }
        }
 
        /**
         * Check if return tag type is void or undefined
         * @param {Object} tag JSDoc tag
         * @returns {boolean} True if its of type void or undefined
         * @private
         */
        function isValidReturnType(tag) {
            return tag.type === null || tag.type.name === "void" || tag.type.type === "UndefinedLiteral";
        }
 
        /**
         * Check if type should be validated based on some exceptions
         * @param {Object} type JSDoc tag
         * @returns {boolean} True if it can be validated
         * @private
         */
        function canTypeBeValidated(type) {
            return type !== "UndefinedLiteral" && // {undefined} as there is no name property available.
                   type !== "NullLiteral" && // {null}
                   type !== "NullableLiteral" && // {?}
                   type !== "FunctionType" && // {function(a)}
                   type !== "AllLiteral"; // {*}
        }
 
        /**
         * Extract the current and expected type based on the input type object
         * @param {Object} type JSDoc tag
         * @returns {Object} current and expected type object
         * @private
         */
        function getCurrentExpectedTypes(type) {
            let currentType;
 
            if (type.name) {
                currentType = type.name;
            } else if (type.expression) {
                currentType = type.expression.name;
            }
 
            const expectedType = currentType && preferType[currentType];
 
            return {
                currentType,
                expectedType
            };
        }
 
        /**
         * Validate type for a given JSDoc node
         * @param {Object} jsdocNode JSDoc node
         * @param {Object} type JSDoc tag
         * @returns {void}
         * @private
         */
        function validateType(jsdocNode, type) {
            if (!type || !canTypeBeValidated(type.type)) {
                return;
            }
 
            const typesToCheck = [];
            let elements = [];
 
            switch (type.type) {
                case "TypeApplication":  // {Array.<String>}
                    elements = type.applications[0].type === "UnionType" ? type.applications[0].elements : type.applications;
                    typesToCheck.push(getCurrentExpectedTypes(type));
                    break;
                case "RecordType":  // {{20:String}}
                    elements = type.fields;
                    break;
                case "UnionType":  // {String|number|Test}
                case "ArrayType":  // {[String, number, Test]}
                    elements = type.elements;
                    break;
                case "FieldType":  // Array.<{count: number, votes: number}>
                    if (type.value) {
                        typesToCheck.push(getCurrentExpectedTypes(type.value));
                    }
                    break;
                default:
                    typesToCheck.push(getCurrentExpectedTypes(type));
            }
 
            elements.forEach(validateType.bind(null, jsdocNode));
 
            typesToCheck.forEach(typeToCheck => {
                if (typeToCheck.expectedType &&
                    typeToCheck.expectedType !== typeToCheck.currentType) {
                    context.report({
                        node: jsdocNode,
                        message: "Use '{{expectedType}}' instead of '{{currentType}}'.",
                        data: {
                            currentType: typeToCheck.currentType,
                            expectedType: typeToCheck.expectedType
                        }
                    });
                }
            });
        }
 
        /**
         * Validate the JSDoc node and output warnings if anything is wrong.
         * @param {ASTNode} node The AST node to check.
         * @returns {void}
         * @private
         */
        function checkJSDoc(node) {
            const jsdocNode = sourceCode.getJSDocComment(node),
                functionData = fns.pop(),
                params = Object.create(null);
            let hasReturns = false,
                hasConstructor = false,
                isInterface = false,
                isOverride = false,
                isAbstract = false,
                jsdoc;
 
            // make sure only to validate JSDoc comments
            if (jsdocNode) {
 
                try {
                    jsdoc = doctrine.parse(jsdocNode.value, {
                        strict: true,
                        unwrap: true,
                        sloppy: true
                    });
                } catch (ex) {
 
                    if (/braces/i.test(ex.message)) {
                        context.report({ node: jsdocNode, message: "JSDoc type missing brace." });
                    } else {
                        context.report({ node: jsdocNode, message: "JSDoc syntax error." });
                    }
 
                    return;
                }
 
                jsdoc.tags.forEach(tag => {
 
                    switch (tag.title.toLowerCase()) {
 
                        case "param":
                        case "arg":
                        case "argument":
                            if (!tag.type) {
                                context.report({ node: jsdocNode, message: "Missing JSDoc parameter type for '{{name}}'.", data: { name: tag.name } });
                            }
 
                            if (!tag.description && requireParamDescription) {
                                context.report({ node: jsdocNode, message: "Missing JSDoc parameter description for '{{name}}'.", data: { name: tag.name } });
                            }
 
                            if (params[tag.name]) {
                                context.report({ node: jsdocNode, message: "Duplicate JSDoc parameter '{{name}}'.", data: { name: tag.name } });
                            } else if (tag.name.indexOf(".") === -1) {
                                params[tag.name] = 1;
                            }
                            break;
 
                        case "return":
                        case "returns":
                            hasReturns = true;
 
                            if (!requireReturn && !functionData.returnPresent && (tag.type === null || !isValidReturnType(tag)) && !isAbstract) {
                                context.report({
                                    node: jsdocNode,
                                    message: "Unexpected @{{title}} tag; function has no return statement.",
                                    data: {
                                        title: tag.title
                                    }
                                });
                            } else {
                                if (requireReturnType && !tag.type) {
                                    context.report({ node: jsdocNode, message: "Missing JSDoc return type." });
                                }
 
                                if (!isValidReturnType(tag) && !tag.description && requireReturnDescription) {
                                    context.report({ node: jsdocNode, message: "Missing JSDoc return description." });
                                }
                            }
 
                            break;
 
                        case "constructor":
                        case "class":
                            hasConstructor = true;
                            break;
 
                        case "override":
                        case "inheritdoc":
                            isOverride = true;
                            break;
 
                        case "abstract":
                        case "virtual":
                            isAbstract = true;
                            break;
 
                        case "interface":
                            isInterface = true;
                            break;
 
                        // no default
                    }
 
                    // check tag preferences
                    if (prefer.hasOwnProperty(tag.title) && tag.title !== prefer[tag.title]) {
                        context.report({ node: jsdocNode, message: "Use @{{name}} instead.", data: { name: prefer[tag.title] } });
                    }
 
                    // validate the types
                    if (checkPreferType && tag.type) {
                        validateType(jsdocNode, tag.type);
                    }
                });
 
                // check for functions missing @returns
                if (!isOverride && !hasReturns && !hasConstructor && !isInterface &&
                    node.parent.kind !== "get" && node.parent.kind !== "constructor" &&
                    node.parent.kind !== "set" && !isTypeClass(node)) {
                    if (requireReturn || functionData.returnPresent) {
                        context.report({
                            node: jsdocNode,
                            message: "Missing JSDoc @{{returns}} for function.",
                            data: {
                                returns: prefer.returns || "returns"
                            }
                        });
                    }
                }
 
                // check the parameters
                const jsdocParams = Object.keys(params);
 
                if (node.params) {
                    node.params.forEach((param, i) => {
                        if (param.type === "AssignmentPattern") {
                            param = param.left;
                        }
 
                        const name = param.name;
 
                        // TODO(nzakas): Figure out logical things to do with destructured, default, rest params
                        if (param.type === "Identifier") {
                            if (jsdocParams[i] && (name !== jsdocParams[i])) {
                                context.report({ node: jsdocNode, message: "Expected JSDoc for '{{name}}' but found '{{jsdocName}}'.", data: {
                                    name,
                                    jsdocName: jsdocParams[i]
                                } });
                            } else if (!params[name] && !isOverride) {
                                context.report({ node: jsdocNode, message: "Missing JSDoc for parameter '{{name}}'.", data: {
                                    name
                                } });
                            }
                        }
                    });
                }
 
                if (options.matchDescription) {
                    const regex = new RegExp(options.matchDescription);
 
                    if (!regex.test(jsdoc.description)) {
                        context.report({ node: jsdocNode, message: "JSDoc description does not satisfy the regex pattern." });
                    }
                }
 
            }
 
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            ArrowFunctionExpression: startFunction,
            FunctionExpression: startFunction,
            FunctionDeclaration: startFunction,
            ClassExpression: startFunction,
            ClassDeclaration: startFunction,
            "ArrowFunctionExpression:exit": checkJSDoc,
            "FunctionExpression:exit": checkJSDoc,
            "FunctionDeclaration:exit": checkJSDoc,
            "ClassExpression:exit": checkJSDoc,
            "ClassDeclaration:exit": checkJSDoc,
            ReturnStatement: addReturn
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/valid-typeof.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/valid-typeof.js

Statements: 12.5% (2 / 16)      Branches: 0% (0 / 25)      Functions: 0% (0 / 3)      Lines: 12.5% (2 / 16)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79                    1                                                                 1                                                                      
/**
 * @fileoverview Ensures that the results of typeof are compared against a valid string
 * @author Ian Christian Myers
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "enforce comparing `typeof` expressions against valid strings",
            category: "Possible Errors",
            recommended: true
        },
 
        schema: [
            {
                type: "object",
                properties: {
                    requireStringLiterals: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ]
    },
 
    create(context) {
 
        const VALID_TYPES = ["symbol", "undefined", "object", "boolean", "number", "string", "function"],
            OPERATORS = ["==", "===", "!=", "!=="];
 
        const requireStringLiterals = context.options[0] && context.options[0].requireStringLiterals;
 
        /**
        * Determines whether a node is a typeof expression.
        * @param {ASTNode} node The node
        * @returns {boolean} `true` if the node is a typeof expression
        */
        function isTypeofExpression(node) {
            return node.type === "UnaryExpression" && node.operator === "typeof";
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
 
            UnaryExpression(node) {
                if (isTypeofExpression(node)) {
                    const parent = context.getAncestors().pop();
 
                    if (parent.type === "BinaryExpression" && OPERATORS.indexOf(parent.operator) !== -1) {
                        const sibling = parent.left === node ? parent.right : parent.left;
 
                        if (sibling.type === "Literal" || sibling.type === "TemplateLiteral" && !sibling.expressions.length) {
                            const value = sibling.type === "Literal" ? sibling.value : sibling.quasis[0].value.cooked;
 
                            if (VALID_TYPES.indexOf(value) === -1) {
                                context.report({ node: sibling, message: "Invalid typeof comparison value." });
                            }
                        } else if (requireStringLiterals && !isTypeofExpression(sibling)) {
                            context.report({ node: sibling, message: "Typeof comparisons should be to string literals." });
                        }
                    }
                }
            }
 
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/vars-on-top.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/vars-on-top.js

Statements: 18.42% (7 / 38)      Branches: 0% (0 / 32)      Functions: 0% (0 / 8)      Lines: 18.42% (7 / 38)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151                      1                                           1                   1                     1                                 1                                                         1                         1                                                                          
/**
 * @fileoverview Rule to enforce var declarations are only at the top of a function.
 * @author Danny Fritz
 * @author Gyandeep Singh
 */
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require `var` declarations be placed at the top of their containing scope",
            category: "Best Practices",
            recommended: false
        },
 
        schema: []
    },
 
    create(context) {
        const errorMessage = "All 'var' declarations must be at the top of the function scope.";
 
        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------
 
        /**
         * @param {ASTNode} node - any node
         * @returns {boolean} whether the given node structurally represents a directive
         */
        function looksLikeDirective(node) {
            return node.type === "ExpressionStatement" &&
                node.expression.type === "Literal" && typeof node.expression.value === "string";
        }
 
        /**
         * Check to see if its a ES6 import declaration
         * @param {ASTNode} node - any node
         * @returns {boolean} whether the given node represents a import declaration
         */
        function looksLikeImport(node) {
            return node.type === "ImportDeclaration" || node.type === "ImportSpecifier" ||
                node.type === "ImportDefaultSpecifier" || node.type === "ImportNamespaceSpecifier";
        }
 
        /**
         * Checks whether a given node is a variable declaration or not.
         *
         * @param {ASTNode} node - any node
         * @returns {boolean} `true` if the node is a variable declaration.
         */
        function isVariableDeclaration(node) {
            return (
                node.type === "VariableDeclaration" ||
                (
                    node.type === "ExportNamedDeclaration" &&
                    node.declaration &&
                    node.declaration.type === "VariableDeclaration"
                )
            );
        }
 
        /**
         * Checks whether this variable is on top of the block body
         * @param {ASTNode} node - The node to check
         * @param {ASTNode[]} statements - collection of ASTNodes for the parent node block
         * @returns {boolean} True if var is on top otherwise false
         */
        function isVarOnTop(node, statements) {
            const l = statements.length;
            let i = 0;
 
            // skip over directives
            for (; i < l; ++i) {
                if (!looksLikeDirective(statements[i]) && !looksLikeImport(statements[i])) {
                    break;
                }
            }
 
            for (; i < l; ++i) {
                if (!isVariableDeclaration(statements[i])) {
                    return false;
                }
                if (statements[i] === node) {
                    return true;
                }
            }
 
            return false;
        }
 
        /**
         * Checks whether variable is on top at the global level
         * @param {ASTNode} node - The node to check
         * @param {ASTNode} parent - Parent of the node
         * @returns {void}
         */
        function globalVarCheck(node, parent) {
            if (!isVarOnTop(node, parent.body)) {
                context.report({ node, message: errorMessage });
            }
        }
 
        /**
         * Checks whether variable is on top at functional block scope level
         * @param {ASTNode} node - The node to check
         * @param {ASTNode} parent - Parent of the node
         * @param {ASTNode} grandParent - Parent of the node's parent
         * @returns {void}
         */
        function blockScopeVarCheck(node, parent, grandParent) {
            if (!(/Function/.test(grandParent.type) &&
                    parent.type === "BlockStatement" &&
                    isVarOnTop(node, parent.body))) {
                context.report({ node, message: errorMessage });
            }
        }
 
        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------
 
        return {
            VariableDeclaration(node) {
                const ancestors = context.getAncestors();
                let parent = ancestors.pop();
                let grandParent = ancestors.pop();
 
                if (node.kind === "var") { // check variable is `var` type and not `let` or `const`
                    if (parent.type === "ExportNamedDeclaration") {
                        node = parent;
                        parent = grandParent;
                        grandParent = ancestors.pop();
                    }
 
                    if (parent.type === "Program") { // That means its a global variable
                        globalVarCheck(node, parent);
                    } else {
                        blockScopeVarCheck(node, parent, grandParent);
                    }
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/wrap-iife.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/wrap-iife.js

Statements: 12.9% (4 / 31)      Branches: 0% (0 / 30)      Functions: 0% (0 / 7)      Lines: 12.9% (4 / 31)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153                      1           1                                                                             1                 1                                                                                                                                                                              
/**
 * @fileoverview Rule to flag when IIFE is not wrapped in parens
 * @author Ilya Volodin
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require parentheses around immediate `function` invocations",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [
            {
                enum: ["outside", "inside", "any"]
            },
            {
                type: "object",
                properties: {
                    functionPrototypeMethods: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ],
 
        fixable: "code"
    },
 
    create(context) {
 
        const style = context.options[0] || "outside";
        const includeFunctionPrototypeMethods = (context.options[1] && context.options[1].functionPrototypeMethods) || false;
 
        const sourceCode = context.getSourceCode();
 
        /**
         * Check if the node is wrapped in ()
         * @param {ASTNode} node node to evaluate
         * @returns {boolean} True if it is wrapped
         * @private
         */
        function wrapped(node) {
            return astUtils.isParenthesised(sourceCode, node);
        }
 
        /**
        * Get the function node from an IIFE
        * @param {ASTNode} node node to evaluate
        * @returns {ASTNode} node that is the function expression of the given IIFE, or null if none exist
        */
        function getFunctionNodeFromIIFE(node) {
            const callee = node.callee;
 
            if (callee.type === "FunctionExpression") {
                return callee;
            }
 
            if (includeFunctionPrototypeMethods &&
                callee.type === "MemberExpression" &&
                callee.object.type === "FunctionExpression" &&
                (astUtils.getStaticPropertyName(callee) === "call" || astUtils.getStaticPropertyName(callee) === "apply")
            ) {
                return callee.object;
            }
 
            return null;
        }
 
 
        return {
            CallExpression(node) {
                const innerNode = getFunctionNodeFromIIFE(node);
 
                if (!innerNode) {
                    return;
                }
 
                const callExpressionWrapped = wrapped(node),
                    functionExpressionWrapped = wrapped(innerNode);
 
                if (!callExpressionWrapped && !functionExpressionWrapped) {
                    context.report({
                        node,
                        message: "Wrap an immediate function invocation in parentheses.",
                        fix(fixer) {
                            const nodeToSurround = style === "inside" ? innerNode : node;
 
                            return fixer.replaceText(nodeToSurround, `(${sourceCode.getText(nodeToSurround)})`);
                        }
                    });
                } else if (style === "inside" && !functionExpressionWrapped) {
                    context.report({
                        node,
                        message: "Wrap only the function expression in parens.",
                        fix(fixer) {
 
                            /*
                             * The outer call expression will always be wrapped at this point.
                             * Replace the range between the end of the function expression and the end of the call expression.
                             * for example, in `(function(foo) {}(bar))`, the range `(bar))` should get replaced with `)(bar)`.
                             * Replace the parens from the outer expression, and parenthesize the function expression.
                             */
                            const parenAfter = sourceCode.getTokenAfter(node);
 
                            return fixer.replaceTextRange(
                                [innerNode.range[1], parenAfter.range[1]],
                                `)${sourceCode.getText().slice(innerNode.range[1], parenAfter.range[0])}`
                            );
                        }
                    });
                } else if (style === "outside" && !callExpressionWrapped) {
                    context.report({
                        node,
                        message: "Move the invocation into the parens that contain the function.",
                        fix(fixer) {
 
                            /*
                             * The inner function expression will always be wrapped at this point.
                             * It's only necessary to replace the range between the end of the function expression
                             * and the call expression. For example, in `(function(foo) {})(bar)`, the range `)(bar)`
                             * should get replaced with `(bar))`.
                             */
                            const parenAfter = sourceCode.getTokenAfter(innerNode);
 
                            return fixer.replaceTextRange(
                                [parenAfter.range[0], node.range[1]],
                                `${sourceCode.getText().slice(parenAfter.range[1], node.range[1])})`
                            );
                        }
                    });
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/wrap-regex.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/wrap-regex.js

Statements: 9.09% (1 / 11)      Branches: 0% (0 / 8)      Functions: 0% (0 / 2)      Lines: 9.09% (1 / 11)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54                      1                                                                                    
/**
 * @fileoverview Rule to flag when regex literals are not wrapped in parens
 * @author Matt DuVall <http://www.mattduvall.com>
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require parenthesis around regex literals",
            category: "Stylistic Issues",
            recommended: false
        },
 
        schema: [],
 
        fixable: "code"
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        return {
 
            Literal(node) {
                const token = sourceCode.getFirstToken(node),
                    nodeType = token.type;
 
                if (nodeType === "RegularExpression") {
                    const source = sourceCode.getTokenBefore(node);
                    const ancestors = context.getAncestors();
                    const grandparent = ancestors[ancestors.length - 1];
 
                    if (grandparent.type === "MemberExpression" && grandparent.object === node &&
                        (!source || source.value !== "(")) {
                        context.report({
                            node,
                            message: "Wrap the regexp literal in parens to disambiguate the slash.",
                            fix: fixer => fixer.replaceText(node, `(${sourceCode.getText(node)})`)
                        });
                    }
                }
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/yield-star-spacing.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/yield-star-spacing.js

Statements: 10.34% (3 / 29)      Branches: 0% (0 / 18)      Functions: 0% (0 / 5)      Lines: 10.34% (3 / 29)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119                      1                                                                                                         1                                                                 1                                          
/**
 * @fileoverview Rule to check the spacing around the * in yield* expressions.
 * @author Bryan Smith
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require or disallow spacing around the `*` in `yield*` expressions",
            category: "ECMAScript 6",
            recommended: false
        },
 
        fixable: "whitespace",
 
        schema: [
            {
                oneOf: [
                    {
                        enum: ["before", "after", "both", "neither"]
                    },
                    {
                        type: "object",
                        properties: {
                            before: { type: "boolean" },
                            after: { type: "boolean" }
                        },
                        additionalProperties: false
                    }
                ]
            }
        ]
    },
 
    create(context) {
        const sourceCode = context.getSourceCode();
 
        const mode = (function(option) {
            if (!option || typeof option === "string") {
                return {
                    before: { before: true, after: false },
                    after: { before: false, after: true },
                    both: { before: true, after: true },
                    neither: { before: false, after: false }
                }[option || "after"];
            }
            return option;
        }(context.options[0]));
 
        /**
         * Checks the spacing between two tokens before or after the star token.
         * @param {string} side Either "before" or "after".
         * @param {Token} leftToken `function` keyword token if side is "before", or
         *     star token if side is "after".
         * @param {Token} rightToken Star token if side is "before", or identifier
         *     token if side is "after".
         * @returns {void}
         */
        function checkSpacing(side, leftToken, rightToken) {
            if (sourceCode.isSpaceBetweenTokens(leftToken, rightToken) !== mode[side]) {
                const after = leftToken.value === "*";
                const spaceRequired = mode[side];
                const node = after ? leftToken : rightToken;
                const type = spaceRequired ? "Missing" : "Unexpected";
                const message = "{{type}} space {{side}} *.";
 
                context.report({
                    node,
                    message,
                    data: {
                        type,
                        side
                    },
                    fix(fixer) {
                        if (spaceRequired) {
                            if (after) {
                                return fixer.insertTextAfter(node, " ");
                            }
                            return fixer.insertTextBefore(node, " ");
                        }
                        return fixer.removeRange([leftToken.range[1], rightToken.range[0]]);
                    }
                });
            }
        }
 
        /**
         * Enforces the spacing around the star if node is a yield* expression.
         * @param {ASTNode} node A yield expression node.
         * @returns {void}
         */
        function checkExpression(node) {
            if (!node.delegate) {
                return;
            }
 
            const tokens = sourceCode.getFirstTokens(node, 3);
            const yieldToken = tokens[0];
            const starToken = tokens[1];
            const nextToken = tokens[2];
 
            checkSpacing("before", yieldToken, starToken);
            checkSpacing("after", starToken, nextToken);
        }
 
        return {
            YieldExpression: checkExpression
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/yoda.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/rules/yoda.js

Statements: 21.67% (13 / 60)      Branches: 0% (0 / 67)      Functions: 0% (0 / 13)      Lines: 22.03% (13 / 59)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310                    1                     1                 1                   1                     1                                       1                                                                   1                                                                                         1                                                                                               1               1                           1                               1                                                         1                                                                                        
/**
 * @fileoverview Rule to require or disallow yoda comparisons
 * @author Nicholas C. Zakas
 */
"use strict";
 
//--------------------------------------------------------------------------
// Requirements
//--------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------
 
/**
 * Determines whether an operator is a comparison operator.
 * @param {string} operator The operator to check.
 * @returns {boolean} Whether or not it is a comparison operator.
 */
function isComparisonOperator(operator) {
    return (/^(==|===|!=|!==|<|>|<=|>=)$/).test(operator);
}
 
/**
 * Determines whether an operator is an equality operator.
 * @param {string} operator The operator to check.
 * @returns {boolean} Whether or not it is an equality operator.
 */
function isEqualityOperator(operator) {
    return (/^(==|===)$/).test(operator);
}
 
/**
 * Determines whether an operator is one used in a range test.
 * Allowed operators are `<` and `<=`.
 * @param {string} operator The operator to check.
 * @returns {boolean} Whether the operator is used in range tests.
 */
function isRangeTestOperator(operator) {
    return ["<", "<="].indexOf(operator) >= 0;
}
 
/**
 * Determines whether a non-Literal node is a negative number that should be
 * treated as if it were a single Literal node.
 * @param {ASTNode} node Node to test.
 * @returns {boolean} True if the node is a negative number that looks like a
 *                    real literal and should be treated as such.
 */
function looksLikeLiteral(node) {
    return (node.type === "UnaryExpression" &&
        node.operator === "-" &&
        node.prefix &&
        node.argument.type === "Literal" &&
        typeof node.argument.value === "number");
}
 
/**
 * Attempts to derive a Literal node from nodes that are treated like literals.
 * @param {ASTNode} node Node to normalize.
 * @param {number} [defaultValue] The default value to be returned if the node
 *                                is not a Literal.
 * @returns {ASTNode} One of the following options.
 *  1. The original node if the node is already a Literal
 *  2. A normalized Literal node with the negative number as the value if the
 *     node represents a negative number literal.
 *  3. The Literal node which has the `defaultValue` argument if it exists.
 *  4. Otherwise `null`.
 */
function getNormalizedLiteral(node, defaultValue) {
    if (node.type === "Literal") {
        return node;
    }
 
    if (looksLikeLiteral(node)) {
        return {
            type: "Literal",
            value: -node.argument.value,
            raw: `-${node.argument.value}`
        };
    }
 
    if (defaultValue) {
        return {
            type: "Literal",
            value: defaultValue,
            raw: String(defaultValue)
        };
    }
 
    return null;
}
 
/**
 * Checks whether two expressions reference the same value. For example:
 *     a = a
 *     a.b = a.b
 *     a[0] = a[0]
 *     a['b'] = a['b']
 * @param   {ASTNode} a Left side of the comparison.
 * @param   {ASTNode} b Right side of the comparison.
 * @returns {boolean}   True if both sides match and reference the same value.
 */
function same(a, b) {
    if (a.type !== b.type) {
        return false;
    }
 
    switch (a.type) {
        case "Identifier":
            return a.name === b.name;
 
        case "Literal":
            return a.value === b.value;
 
        case "MemberExpression": {
            const nameA = astUtils.getStaticPropertyName(a);
 
            // x.y = x["y"]
            if (nameA) {
                return (
                    same(a.object, b.object) &&
                    nameA === astUtils.getStaticPropertyName(b)
                );
            }
 
            // x[0] = x[0]
            // x[y] = x[y]
            // x.y = x.y
            return (
                a.computed === b.computed &&
                same(a.object, b.object) &&
                same(a.property, b.property)
            );
        }
 
        case "ThisExpression":
            return true;
 
        default:
            return false;
    }
}
 
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
 
module.exports = {
    meta: {
        docs: {
            description: "require or disallow \"Yoda\" conditions",
            category: "Best Practices",
            recommended: false
        },
 
        schema: [
            {
                enum: ["always", "never"]
            },
            {
                type: "object",
                properties: {
                    exceptRange: {
                        type: "boolean"
                    },
                    onlyEquality: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ],
 
        fixable: "code"
    },
 
    create(context) {
 
        // Default to "never" (!always) if no option
        const always = (context.options[0] === "always");
        const exceptRange = (context.options[1] && context.options[1].exceptRange);
        const onlyEquality = (context.options[1] && context.options[1].onlyEquality);
 
        const sourceCode = context.getSourceCode();
 
        /**
         * Determines whether node represents a range test.
         * A range test is a "between" test like `(0 <= x && x < 1)` or an "outside"
         * test like `(x < 0 || 1 <= x)`. It must be wrapped in parentheses, and
         * both operators must be `<` or `<=`. Finally, the literal on the left side
         * must be less than or equal to the literal on the right side so that the
         * test makes any sense.
         * @param {ASTNode} node LogicalExpression node to test.
         * @returns {boolean} Whether node is a range test.
         */
        function isRangeTest(node) {
            const left = node.left,
                right = node.right;
 
            /**
             * Determines whether node is of the form `0 <= x && x < 1`.
             * @returns {boolean} Whether node is a "between" range test.
             */
            function isBetweenTest() {
                let leftLiteral, rightLiteral;
 
                return (node.operator === "&&" &&
                    (leftLiteral = getNormalizedLiteral(left.left)) &&
                    (rightLiteral = getNormalizedLiteral(right.right, Number.POSITIVE_INFINITY)) &&
                    leftLiteral.value <= rightLiteral.value &&
                    same(left.right, right.left));
            }
 
            /**
             * Determines whether node is of the form `x < 0 || 1 <= x`.
             * @returns {boolean} Whether node is an "outside" range test.
             */
            function isOutsideTest() {
                let leftLiteral, rightLiteral;
 
                return (node.operator === "||" &&
                    (leftLiteral = getNormalizedLiteral(left.right, Number.NEGATIVE_INFINITY)) &&
                    (rightLiteral = getNormalizedLiteral(right.left)) &&
                    leftLiteral.value <= rightLiteral.value &&
                    same(left.left, right.right));
            }
 
            /**
             * Determines whether node is wrapped in parentheses.
             * @returns {boolean} Whether node is preceded immediately by an open
             *                    paren token and followed immediately by a close
             *                    paren token.
             */
            function isParenWrapped() {
                return astUtils.isParenthesised(sourceCode, node);
            }
 
            return (node.type === "LogicalExpression" &&
                left.type === "BinaryExpression" &&
                right.type === "BinaryExpression" &&
                isRangeTestOperator(left.operator) &&
                isRangeTestOperator(right.operator) &&
                (isBetweenTest() || isOutsideTest()) &&
                isParenWrapped());
        }
 
        const OPERATOR_FLIP_MAP = {
            "===": "===",
            "!==": "!==",
            "==": "==",
            "!=": "!=",
            "<": ">",
            ">": "<",
            "<=": ">=",
            ">=": "<="
        };
 
        /**
        * Returns a string representation of a BinaryExpression node with its sides/operator flipped around.
        * @param {ASTNode} node The BinaryExpression node
        * @returns {string} A string representation of the node with the sides and operator flipped
        */
        function getFlippedString(node) {
            const operatorToken = sourceCode.getFirstTokenBetween(node.left, node.right, token => token.value === node.operator);
            const textBeforeOperator = sourceCode.getText().slice(sourceCode.getTokenBefore(operatorToken).range[1], operatorToken.range[0]);
            const textAfterOperator = sourceCode.getText().slice(operatorToken.range[1], sourceCode.getTokenAfter(operatorToken).range[0]);
            const leftText = sourceCode.getText().slice(node.range[0], sourceCode.getTokenBefore(operatorToken).range[1]);
            const rightText = sourceCode.getText().slice(sourceCode.getTokenAfter(operatorToken).range[0], node.range[1]);
 
            return rightText + textBeforeOperator + OPERATOR_FLIP_MAP[operatorToken.value] + textAfterOperator + leftText;
        }
 
        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------
 
        return {
            BinaryExpression(node) {
                const expectedLiteral = always ? node.left : node.right;
                const expectedNonLiteral = always ? node.right : node.left;
 
                // If `expectedLiteral` is not a literal, and `expectedNonLiteral` is a literal, raise an error.
                if (
                    (expectedNonLiteral.type === "Literal" || looksLikeLiteral(expectedNonLiteral)) &&
                    !(expectedLiteral.type === "Literal" || looksLikeLiteral(expectedLiteral)) &&
                    !(!isEqualityOperator(node.operator) && onlyEquality) &&
                    isComparisonOperator(node.operator) &&
                    !(exceptRange && isRangeTest(context.getAncestors().pop()))
                ) {
                    context.report({
                        node,
                        message: "Expected literal to be on the {{expectedSide}} side of {{operator}}.",
                        data: {
                            operator: node.operator,
                            expectedSide: always ? "left" : "right"
                        },
                        fix: fixer => fixer.replaceText(node, getFlippedString(node))
                    });
                }
 
            }
        };
 
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/testers/

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/testers/

Statements: 16.25% (26 / 160)      Branches: 6.82% (6 / 88)      Functions: 9.52% (2 / 21)      Lines: 16.25% (26 / 160)      Ignored: none     

All files » node-npmtest-eslint/node_modules/eslint/lib/testers/
File Statements Branches Functions Lines
rule-tester.js 16.25% (26 / 160) 6.82% (6 / 88) 9.52% (2 / 21) 16.25% (26 / 160)
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/testers/rule-tester.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/testers/rule-tester.js

Statements: 16.25% (26 / 160)      Branches: 6.82% (6 / 88)      Functions: 9.52% (2 / 21)      Lines: 16.25% (26 / 160)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570                                                                                    1                                   1 1           1               1   1                 1                                                   1                                               1                                                   1                           1                 1         1 1   1                 1             1     14                         14                         1                                                                                                     1                                                                                                                                                                                                                                 1                               1                                     1                                         1                                                                                                                                                                                                                         1    
/**
 * @fileoverview Mocha test wrapper
 * @author Ilya Volodin
 */
"use strict";
 
/* global describe, it */
 
/*
 * This is a wrapper around mocha to allow for DRY unittests for eslint
 * Format:
 * RuleTester.add("{ruleName}", {
 *      valid: [
 *          "{code}",
 *          { code: "{code}", options: {options}, global: {globals}, globals: {globals}, parser: "{parser}", settings: {settings} }
 *      ],
 *      invalid: [
 *          { code: "{code}", errors: {numErrors} },
 *          { code: "{code}", errors: ["{errorMessage}"] },
 *          { code: "{code}", options: {options}, global: {globals}, parser: "{parser}", settings: {settings}, errors: [{ message: "{errorMessage}", type: "{errorNodeType}"}] }
 *      ]
 *  });
 *
 * Variables:
 * {code} - String that represents the code to be tested
 * {options} - Arguments that are passed to the configurable rules.
 * {globals} - An object representing a list of variables that are
 *             registered as globals
 * {parser} - String representing the parser to use
 * {settings} - An object representing global settings for all rules
 * {numErrors} - If failing case doesn't need to check error message,
 *               this integer will specify how many errors should be
 *               received
 * {errorMessage} - Message that is returned by the rule on failure
 * {errorNodeType} - AST node type that is returned by they rule as
 *                   a cause of the failure.
 */
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const lodash = require("lodash"),
    assert = require("assert"),
    util = require("util"),
    validator = require("../config/config-validator"),
    validate = require("is-my-json-valid"),
    eslint = require("../eslint"),
    rules = require("../rules"),
    metaSchema = require("../../conf/json-schema-schema.json"),
    SourceCodeFixer = require("../util/source-code-fixer");
 
//------------------------------------------------------------------------------
// Private Members
//------------------------------------------------------------------------------
 
/*
 * testerDefaultConfig must not be modified as it allows to reset the tester to
 * the initial default configuration
 */
const testerDefaultConfig = { rules: {} };
let defaultConfig = { rules: {} };
 
/*
 * List every parameters possible on a test case that are not related to eslint
 * configuration
 */
const RuleTesterParameters = [
    "code",
    "filename",
    "options",
    "args",
    "errors"
];
 
const validateSchema = validate(metaSchema, { verbose: true });
 
const hasOwnProperty = Function.call.bind(Object.hasOwnProperty);
 
/**
 * Clones a given value deeply.
 * Note: This ignores `parent` property.
 *
 * @param {any} x - A value to clone.
 * @returns {any} A cloned value.
 */
function cloneDeeplyExcludesParent(x) {
    if (typeof x === "object" && x !== null) {
        if (Array.isArray(x)) {
            return x.map(cloneDeeplyExcludesParent);
        }
 
        const retv = {};
 
        for (const key in x) {
            if (key !== "parent" && hasOwnProperty(x, key)) {
                retv[key] = cloneDeeplyExcludesParent(x[key]);
            }
        }
 
        return retv;
    }
 
    return x;
}
 
/**
 * Freezes a given value deeply.
 *
 * @param {any} x - A value to freeze.
 * @returns {void}
 */
function freezeDeeply(x) {
    if (typeof x === "object" && x !== null) {
        if (Array.isArray(x)) {
            x.forEach(freezeDeeply);
        } else {
            for (const key in x) {
                if (key !== "parent" && hasOwnProperty(x, key)) {
                    freezeDeeply(x[key]);
                }
            }
        }
        Object.freeze(x);
    }
}
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
/**
 * Creates a new instance of RuleTester.
 * @param {Object} [testerConfig] Optional, extra configuration for the tester
 * @constructor
 */
function RuleTester(testerConfig) {
 
    /**
     * The configuration to use for this tester. Combination of the tester
     * configuration and the default configuration.
     * @type {Object}
     */
    this.testerConfig = lodash.merge(
 
        // we have to clone because merge uses the first argument for recipient
        lodash.cloneDeep(defaultConfig),
        testerConfig
    );
 
    /**
     * Rule definitions to define before tests.
     * @type {Object}
     */
    this.rules = {};
}
 
/**
 * Set the configuration to use for all future tests
 * @param {Object} config the configuration to use.
 * @returns {void}
 */
RuleTester.setDefaultConfig = function(config) {
    if (typeof config !== "object") {
        throw new Error("RuleTester.setDefaultConfig: config must be an object");
    }
    defaultConfig = config;
 
    // Make sure the rules object exists since it is assumed to exist later
    defaultConfig.rules = defaultConfig.rules || {};
};
 
/**
 * Get the current configuration used for all tests
 * @returns {Object} the current configuration
 */
RuleTester.getDefaultConfig = function() {
    return defaultConfig;
};
 
/**
 * Reset the configuration to the initial configuration of the tester removing
 * any changes made until now.
 * @returns {void}
 */
RuleTester.resetDefaultConfig = function() {
    defaultConfig = lodash.cloneDeep(testerDefaultConfig);
};
 
// default separators for testing
const DESCRIBE = Symbol("describe");
const IT = Symbol("it");
 
RuleTester[DESCRIBE] = RuleTester[IT] = null;
 
/**
 * This is `it` or `describe` if those don't exist.
 * @this {Mocha}
 * @param {string} text - The description of the test case.
 * @param {Function} method - The logic of the test case.
 * @returns {any} Returned value of `method`.
 */
function defaultHandler(text, method) {
    return method.apply(this);
}
 
// If people use `mocha test.js --watch` command, `describe` and `it` function
// instances are different for each execution. So this should get fresh instance
// always.
Object.defineProperties(RuleTester, {
    describe: {
        get() {
            return (
                RuleTester[DESCRIBE] ||
                (typeof describe === "function" ? describe : defaultHandler)
            );
        },
        set(value) {
            RuleTester[DESCRIBE] = value;
        },
        configurable: true,
        enumerable: true
    },
    it: {
        get() {
            return (
                RuleTester[IT] ||
                (typeof it === "function" ? it : defaultHandler)
            );
        },
        set(value) {
            RuleTester[IT] = value;
        },
        configurable: true,
        enumerable: true
    }
});
 
RuleTester.prototype = {
 
    /**
     * Define a rule for one particular run of tests.
     * @param {string} name The name of the rule to define.
     * @param {Function} rule The rule definition.
     * @returns {void}
     */
    defineRule(name, rule) {
        this.rules[name] = rule;
    },
 
    /**
     * Adds a new rule test to execute.
     * @param {string} ruleName The name of the rule to run.
     * @param {Function} rule The rule to test.
     * @param {Object} test The collection of tests to run.
     * @returns {void}
     */
    run(ruleName, rule, test) {
 
        const testerConfig = this.testerConfig,
            requiredScenarios = ["valid", "invalid"],
            scenarioErrors = [],
            result = {};
 
        if (lodash.isNil(test) || typeof test !== "object") {
            throw new Error(`Test Scenarios for rule ${ruleName} : Could not find test scenario object`);
        }
 
        requiredScenarios.forEach(scenarioType => {
            if (lodash.isNil(test[scenarioType])) {
                scenarioErrors.push(`Could not find any ${scenarioType} test scenarios`);
            }
        });
 
        if (scenarioErrors.length > 0) {
            throw new Error([
                `Test Scenarios for rule ${ruleName} is invalid:`
            ].concat(scenarioErrors).join("\n"));
        }
 
        /* eslint-disable no-shadow */
 
        /**
         * Run the rule for the given item
         * @param {string} ruleName name of the rule
         * @param {string|Object} item Item to run the rule against
         * @returns {Object} Eslint run result
         * @private
         */
        function runRuleForItem(ruleName, item) {
            let config = lodash.cloneDeep(testerConfig),
                code, filename, beforeAST, afterAST;
 
            if (typeof item === "string") {
                code = item;
            } else {
                code = item.code;
 
                // Assumes everything on the item is a config except for the
                // parameters used by this tester
                const itemConfig = lodash.omit(item, RuleTesterParameters);
 
                // Create the config object from the tester config and this item
                // specific configurations.
                config = lodash.merge(
                    config,
                    itemConfig
                );
            }
 
            if (item.filename) {
                filename = item.filename;
            }
 
            if (item.options) {
                const options = item.options.concat();
 
                options.unshift(1);
                config.rules[ruleName] = options;
            } else {
                config.rules[ruleName] = 1;
            }
 
            eslint.defineRule(ruleName, rule);
 
            const schema = validator.getRuleOptionsSchema(ruleName);
 
            if (schema) {
                validateSchema(schema);
 
                if (validateSchema.errors) {
                    throw new Error([
                        `Schema for rule ${ruleName} is invalid:`
                    ].concat(validateSchema.errors.map(error => `\t${error.field}: ${error.message}`)).join("\n"));
                }
            }
 
            validator.validate(config, "rule-tester");
 
            /*
             * Setup AST getters.
             * The goal is to check whether or not AST was modified when
             * running the rule under test.
             */
            eslint.reset();
 
            eslint.on("Program", node => {
                beforeAST = cloneDeeplyExcludesParent(node);
            });
 
            eslint.on("Program:exit", node => {
                afterAST = node;
            });
 
            // Freezes rule-context properties.
            const originalGet = rules.get;
 
            try {
                rules.get = function(ruleId) {
                    const rule = originalGet(ruleId);
 
                    if (typeof rule === "function") {
                        return function(context) {
                            Object.freeze(context);
                            freezeDeeply(context.options);
                            freezeDeeply(context.settings);
                            freezeDeeply(context.parserOptions);
 
                            return rule(context);
                        };
                    }
                    return {
                        meta: rule.meta,
                        create(context) {
                            Object.freeze(context);
                            freezeDeeply(context.options);
                            freezeDeeply(context.settings);
                            freezeDeeply(context.parserOptions);
 
                            return rule.create(context);
                        }
                    };
 
                };
 
                return {
                    messages: eslint.verify(code, config, filename, true),
                    beforeAST,
                    afterAST: cloneDeeplyExcludesParent(afterAST)
                };
            } finally {
                rules.get = originalGet;
            }
        }
 
        /**
         * Check if the AST was changed
         * @param {ASTNode} beforeAST AST node before running
         * @param {ASTNode} afterAST AST node after running
         * @returns {void}
         * @private
         */
        function assertASTDidntChange(beforeAST, afterAST) {
            if (!lodash.isEqual(beforeAST, afterAST)) {
 
                // Not using directly to avoid performance problem in node 6.1.0. See #6111
                assert.deepEqual(beforeAST, afterAST, "Rule should not modify AST.");
            }
        }
 
        /**
         * Check if the template is valid or not
         * all valid cases go through this
         * @param {string} ruleName name of the rule
         * @param {string|Object} item Item to run the rule against
         * @returns {void}
         * @private
         */
        function testValidTemplate(ruleName, item) {
            const result = runRuleForItem(ruleName, item);
            const messages = result.messages;
 
            assert.equal(messages.length, 0, util.format("Should have no errors but had %d: %s",
                        messages.length, util.inspect(messages)));
 
            assertASTDidntChange(result.beforeAST, result.afterAST);
        }
 
        /**
         * Asserts that the message matches its expected value. If the expected
         * value is a regular expression, it is checked against the actual
         * value.
         * @param {string} actual Actual value
         * @param {string|RegExp} expected Expected value
         * @returns {void}
         * @private
         */
        function assertMessageMatches(actual, expected) {
            if (expected instanceof RegExp) {
 
                // assert.js doesn't have a built-in RegExp match function
                assert.ok(
                    expected.test(actual),
                    `Expected '${actual}' to match ${expected}`
                );
            } else {
                assert.equal(actual, expected);
            }
        }
 
        /**
         * Check if the template is invalid or not
         * all invalid cases go through this.
         * @param {string} ruleName name of the rule
         * @param {string|Object} item Item to run the rule against
         * @returns {void}
         * @private
         */
        function testInvalidTemplate(ruleName, item) {
            assert.ok(item.errors || item.errors === 0,
                `Did not specify errors for an invalid test of ${ruleName}`);
 
            const result = runRuleForItem(ruleName, item);
            const messages = result.messages;
 
 
 
            if (typeof item.errors === "number") {
                assert.equal(messages.length, item.errors, util.format("Should have %d error%s but had %d: %s",
                    item.errors, item.errors === 1 ? "" : "s", messages.length, util.inspect(messages)));
            } else {
                assert.equal(messages.length, item.errors.length,
                    util.format("Should have %d error%s but had %d: %s",
                    item.errors.length, item.errors.length === 1 ? "" : "s", messages.length, util.inspect(messages)));
 
                for (let i = 0, l = item.errors.length; i < l; i++) {
                    assert.ok(!("fatal" in messages[i]), `A fatal parsing error occurred: ${messages[i].message}`);
                    assert.equal(messages[i].ruleId, ruleName, "Error rule name should be the same as the name of the rule being tested");
 
                    if (typeof item.errors[i] === "string" || item.errors[i] instanceof RegExp) {
 
                        // Just an error message.
                        assertMessageMatches(messages[i].message, item.errors[i]);
                    } else if (typeof item.errors[i] === "object") {
 
                        /*
                         * Error object.
                         * This may have a message, node type, line, and/or
                         * column.
                         */
                        if (item.errors[i].message) {
                            assertMessageMatches(messages[i].message, item.errors[i].message);
                        }
 
                        if (item.errors[i].type) {
                            assert.equal(messages[i].nodeType, item.errors[i].type, `Error type should be ${item.errors[i].type}, found ${messages[i].nodeType}`);
                        }
 
                        if (item.errors[i].hasOwnProperty("line")) {
                            assert.equal(messages[i].line, item.errors[i].line, `Error line should be ${item.errors[i].line}`);
                        }
 
                        if (item.errors[i].hasOwnProperty("column")) {
                            assert.equal(messages[i].column, item.errors[i].column, `Error column should be ${item.errors[i].column}`);
                        }
 
                        if (item.errors[i].hasOwnProperty("endLine")) {
                            assert.equal(messages[i].endLine, item.errors[i].endLine, `Error endLine should be ${item.errors[i].endLine}`);
                        }
 
                        if (item.errors[i].hasOwnProperty("endColumn")) {
                            assert.equal(messages[i].endColumn, item.errors[i].endColumn, `Error endColumn should be ${item.errors[i].endColumn}`);
                        }
                    } else {
 
                        // Message was an unexpected type
                        assert.fail(messages[i], null, "Error should be a string, object, or RegExp.");
                    }
                }
            }
 
            if (item.hasOwnProperty("output")) {
                if (item.output === null) {
                    assert.strictEqual(
                        messages.filter(message => message.fix).length,
                        0,
                        "Expected no autofixes to be suggested"
                    );
                } else {
                    const fixResult = SourceCodeFixer.applyFixes(eslint.getSourceCode(), messages);
 
                    assert.equal(fixResult.output, item.output, "Output is incorrect.");
                }
            }
 
            assertASTDidntChange(result.beforeAST, result.afterAST);
        }
 
        /*
         * This creates a mocha test suite and pipes all supplied info through
         * one of the templates above.
         */
        RuleTester.describe(ruleName, () => {
            RuleTester.describe("valid", () => {
                test.valid.forEach(valid => {
                    RuleTester.it(typeof valid === "object" ? valid.code : valid, () => {
                        eslint.defineRules(this.rules);
                        testValidTemplate(ruleName, valid);
                    });
                });
            });
 
            RuleTester.describe("invalid", () => {
                test.invalid.forEach(invalid => {
                    RuleTester.it(invalid.code, () => {
                        eslint.defineRules(this.rules);
                        testInvalidTemplate(ruleName, invalid);
                    });
                });
            });
        });
 
        return result.suite;
    }
};
 
 
module.exports = RuleTester;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/

Statements: 20.41% (50 / 245)      Branches: 0% (0 / 122)      Functions: 1.89% (1 / 53)      Lines: 20.41% (50 / 245)      Ignored: none     

All files » node-npmtest-eslint/node_modules/eslint/lib/token-store/
File Statements Branches Functions Lines
backward-token-comment-cursor.js 15.79% (3 / 19) 0% (0 / 14) 0% (0 / 2) 15.79% (3 / 19)
backward-token-cursor.js 23.08% (3 / 13) 0% (0 / 4) 0% (0 / 3) 23.08% (3 / 13)
cursor.js 12.5% (1 / 8) 0% (0 / 2) 0% (0 / 4) 12.5% (1 / 8)
cursors.js 52.38% (11 / 21) 0% (0 / 8) 33.33% (1 / 3) 52.38% (11 / 21)
decorative-cursor.js 28.57% (2 / 7) 100% (0 / 0) 0% (0 / 2) 28.57% (2 / 7)
filter-cursor.js 22.22% (2 / 9) 0% (0 / 2) 0% (0 / 2) 22.22% (2 / 9)
forward-token-comment-cursor.js 15.79% (3 / 19) 0% (0 / 14) 0% (0 / 2) 15.79% (3 / 19)
forward-token-cursor.js 21.43% (3 / 14) 0% (0 / 4) 0% (0 / 4) 21.43% (3 / 14)
index.js 12.5% (11 / 88) 0% (0 / 46) 0% (0 / 22) 12.5% (11 / 88)
limit-cursor.js 25% (2 / 8) 0% (0 / 2) 0% (0 / 2) 25% (2 / 8)
padded-token-cursor.js 40% (2 / 5) 100% (0 / 0) 0% (0 / 1) 40% (2 / 5)
skip-cursor.js 22.22% (2 / 9) 0% (0 / 2) 0% (0 / 2) 22.22% (2 / 9)
utils.js 20% (5 / 25) 0% (0 / 24) 0% (0 / 4) 20% (5 / 25)
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/backward-token-comment-cursor.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/backward-token-comment-cursor.js

Statements: 15.79% (3 / 19)      Branches: 0% (0 / 14)      Functions: 0% (0 / 2)      Lines: 15.79% (3 / 19)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59                    1 1                 1                                                                            
/**
 * @fileoverview Define the cursor which iterates tokens and comments in reverse.
 * @author Toru Nagashima
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const Cursor = require("./cursor");
const utils = require("./utils");
 
//------------------------------------------------------------------------------
// Exports
//------------------------------------------------------------------------------
 
/**
 * The cursor which iterates tokens and comments in reverse.
 */
module.exports = class BackwardTokenCommentCursor extends Cursor {
 
    /**
     * Initializes this cursor.
     * @param {Token[]} tokens - The array of tokens.
     * @param {Comment[]} comments - The array of comments.
     * @param {Object} indexMap - The map from locations to indices in `tokens`.
     * @param {number} startLoc - The start location of the iteration range.
     * @param {number} endLoc - The end location of the iteration range.
     */
    constructor(tokens, comments, indexMap, startLoc, endLoc) {
        super();
        this.tokens = tokens;
        this.comments = comments;
        this.tokenIndex = utils.getLastIndex(tokens, indexMap, endLoc);
        this.commentIndex = utils.search(comments, endLoc) - 1;
        this.border = startLoc;
    }
 
    /** @inheritdoc */
    moveNext() {
        const token = (this.tokenIndex >= 0) ? this.tokens[this.tokenIndex] : null;
        const comment = (this.commentIndex >= 0) ? this.comments[this.commentIndex] : null;
 
        if (token && (!comment || token.range[1] > comment.range[1])) {
            this.current = token;
            this.tokenIndex -= 1;
        } else if (comment) {
            this.current = comment;
            this.commentIndex -= 1;
        } else {
            this.current = null;
        }
 
        return Boolean(this.current) && (this.border === -1 || this.current.range[0] >= this.border);
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/backward-token-cursor.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/backward-token-cursor.js

Statements: 23.08% (3 / 13)      Branches: 0% (0 / 4)      Functions: 0% (0 / 3)      Lines: 23.08% (3 / 13)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58                    1 1                 1                                                                          
/**
 * @fileoverview Define the cursor which iterates tokens only in reverse.
 * @author Toru Nagashima
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const Cursor = require("./cursor");
const utils = require("./utils");
 
//------------------------------------------------------------------------------
// Exports
//------------------------------------------------------------------------------
 
/**
 * The cursor which iterates tokens only in reverse.
 */
module.exports = class BackwardTokenCursor extends Cursor {
 
    /**
     * Initializes this cursor.
     * @param {Token[]} tokens - The array of tokens.
     * @param {Comment[]} comments - The array of comments.
     * @param {Object} indexMap - The map from locations to indices in `tokens`.
     * @param {number} startLoc - The start location of the iteration range.
     * @param {number} endLoc - The end location of the iteration range.
     */
    constructor(tokens, comments, indexMap, startLoc, endLoc) {
        super();
        this.tokens = tokens;
        this.index = utils.getLastIndex(tokens, indexMap, endLoc);
        this.indexEnd = utils.getFirstIndex(tokens, indexMap, startLoc);
    }
 
    /** @inheritdoc */
    moveNext() {
        if (this.index >= this.indexEnd) {
            this.current = this.tokens[this.index];
            this.index -= 1;
            return true;
        }
        return false;
    }
 
    //
    // Shorthand for performance.
    //
 
    /** @inheritdoc */
    getOneToken() {
        return (this.index >= this.indexEnd) ? this.tokens[this.index] : null;
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/cursor.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/cursor.js

Statements: 12.5% (1 / 8)      Branches: 0% (0 / 2)      Functions: 0% (0 / 4)      Lines: 12.5% (1 / 8)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78                                                                  1                                                                                        
/**
 * @fileoverview Define the abstract class about cursors which iterate tokens.
 * @author Toru Nagashima
 */
"use strict";
 
//------------------------------------------------------------------------------
// Exports
//------------------------------------------------------------------------------
 
/**
 * The abstract class about cursors which iterate tokens.
 *
 * This class has 2 abstract methods.
 *
 * - `current: Token | Comment | null` ... The current token.
 * - `moveNext(): boolean` ... Moves this cursor to the next token. If the next token didn't exist, it returns `false`.
 *
 * This is similar to ES2015 Iterators.
 * However, Iterators were slow (at 2017-01), so I created this class as similar to C# IEnumerable.
 *
 * There are the following known sub classes.
 *
 * - ForwardTokenCursor .......... The cursor which iterates tokens only.
 * - BackwardTokenCursor ......... The cursor which iterates tokens only in reverse.
 * - ForwardTokenCommentCursor ... The cursor which iterates tokens and comments.
 * - BackwardTokenCommentCursor .. The cursor which iterates tokens and comments in reverse.
 * - DecorativeCursor
 *     - FilterCursor ............ The cursor which ignores the specified tokens.
 *     - SkipCursor .............. The cursor which ignores the first few tokens.
 *     - LimitCursor ............. The cursor which limits the count of tokens.
 *
 */
module.exports = class Cursor {
 
    /**
     * Initializes this cursor.
     */
    constructor() {
        this.current = null;
    }
 
    /**
     * Gets the first token.
     * This consumes this cursor.
     * @returns {Token|Comment} The first token or null.
     */
    getOneToken() {
        return this.moveNext() ? this.current : null;
    }
 
    /**
     * Gets the first tokens.
     * This consumes this cursor.
     * @returns {(Token|Comment)[]} All tokens.
     */
    getAllTokens() {
        const tokens = [];
 
        while (this.moveNext()) {
            tokens.push(this.current);
        }
 
        return tokens;
    }
 
    /**
     * Moves this cursor to the next token.
     * @returns {boolean} `true` if the next token exists.
     * @abstract
     */
    /* istanbul ignore next */
    moveNext() { // eslint-disable-line class-methods-use-this
        throw new Error("Not implemented.");
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/cursors.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/cursors.js

Statements: 52.38% (11 / 21)      Branches: 0% (0 / 8)      Functions: 33.33% (1 / 3)      Lines: 52.38% (11 / 21)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94                    1 1 1 1 1 1 1                                   2 2                                                                                                             1 1    
/**
 * @fileoverview Define 2 token factories; forward and backward.
 * @author Toru Nagashima
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const BackwardTokenCommentCursor = require("./backward-token-comment-cursor");
const BackwardTokenCursor = require("./backward-token-cursor");
const FilterCursor = require("./filter-cursor");
const ForwardTokenCommentCursor = require("./forward-token-comment-cursor");
const ForwardTokenCursor = require("./forward-token-cursor");
const LimitCursor = require("./limit-cursor");
const SkipCursor = require("./skip-cursor");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * The cursor factory.
 * @private
 */
class CursorFactory {
 
    /**
     * Initializes this cursor.
     * @param {Function} TokenCursor - The class of the cursor which iterates tokens only.
     * @param {Function} TokenCommentCursor - The class of the cursor which iterates the mix of tokens and comments.
     */
    constructor(TokenCursor, TokenCommentCursor) {
        this.TokenCursor = TokenCursor;
        this.TokenCommentCursor = TokenCommentCursor;
    }
 
    /**
     * Creates a base cursor instance that can be decorated by createCursor.
     *
     * @param {Token[]} tokens - The array of tokens.
     * @param {Comment[]} comments - The array of comments.
     * @param {Object} indexMap - The map from locations to indices in `tokens`.
     * @param {number} startLoc - The start location of the iteration range.
     * @param {number} endLoc - The end location of the iteration range.
     * @param {boolean} includeComments - The flag to iterate comments as well.
     * @returns {Cursor} The created base cursor.
     */
    createBaseCursor(tokens, comments, indexMap, startLoc, endLoc, includeComments) {
        const Cursor = includeComments ? this.TokenCommentCursor : this.TokenCursor;
 
        return new Cursor(tokens, comments, indexMap, startLoc, endLoc);
    }
 
    /**
     * Creates a cursor that iterates tokens with normalized options.
     *
     * @param {Token[]} tokens - The array of tokens.
     * @param {Comment[]} comments - The array of comments.
     * @param {Object} indexMap - The map from locations to indices in `tokens`.
     * @param {number} startLoc - The start location of the iteration range.
     * @param {number} endLoc - The end location of the iteration range.
     * @param {boolean} includeComments - The flag to iterate comments as well.
     * @param {Function|null} filter - The predicate function to choose tokens.
     * @param {number} skip - The count of tokens the cursor skips.
     * @param {number} count - The maximum count of tokens the cursor iterates. Zero is no iteration for backward compatibility.
     * @returns {Cursor} The created cursor.
     */
    createCursor(tokens, comments, indexMap, startLoc, endLoc, includeComments, filter, skip, count) {
        let cursor = this.createBaseCursor(tokens, comments, indexMap, startLoc, endLoc, includeComments);
 
        if (filter) {
            cursor = new FilterCursor(cursor, filter);
        }
        if (skip >= 1) {
            cursor = new SkipCursor(cursor, skip);
        }
        if (count >= 0) {
            cursor = new LimitCursor(cursor, count);
        }
 
        return cursor;
    }
}
 
//------------------------------------------------------------------------------
// Exports
//------------------------------------------------------------------------------
 
exports.forward = new CursorFactory(ForwardTokenCursor, ForwardTokenCommentCursor);
exports.backward = new CursorFactory(BackwardTokenCursor, BackwardTokenCommentCursor);
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/decorative-cursor.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/decorative-cursor.js

Statements: 28.57% (2 / 7)      Branches: 100% (0 / 0)      Functions: 0% (0 / 2)      Lines: 28.57% (2 / 7)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41                    1                 1                                          
/**
 * @fileoverview Define the abstract class about cursors which manipulate another cursor.
 * @author Toru Nagashima
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const Cursor = require("./cursor");
 
//------------------------------------------------------------------------------
// Exports
//------------------------------------------------------------------------------
 
/**
 * The abstract class about cursors which manipulate another cursor.
 */
module.exports = class DecorativeCursor extends Cursor {
 
    /**
     * Initializes this cursor.
     * @param {Cursor} cursor - The cursor to be decorated.
     */
    constructor(cursor) {
        super();
        this.cursor = cursor;
    }
 
    /** @inheritdoc */
    moveNext() {
        const retv = this.cursor.moveNext();
 
        this.current = this.cursor.current;
 
        return retv;
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/filter-cursor.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/filter-cursor.js

Statements: 22.22% (2 / 9)      Branches: 0% (0 / 2)      Functions: 0% (0 / 2)      Lines: 22.22% (2 / 9)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45                    1                 1                                                  
/**
 * @fileoverview Define the cursor which ignores specified tokens.
 * @author Toru Nagashima
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const DecorativeCursor = require("./decorative-cursor");
 
//------------------------------------------------------------------------------
// Exports
//------------------------------------------------------------------------------
 
/**
 * The decorative cursor which ignores specified tokens.
 */
module.exports = class FilterCursor extends DecorativeCursor {
 
    /**
     * Initializes this cursor.
     * @param {Cursor} cursor - The cursor to be decorated.
     * @param {Function} predicate - The predicate function to decide tokens this cursor iterates.
     */
    constructor(cursor, predicate) {
        super(cursor);
        this.predicate = predicate;
    }
 
    /** @inheritdoc */
    moveNext() {
        const predicate = this.predicate;
 
        while (super.moveNext()) {
            if (predicate(this.current)) {
                return true;
            }
        }
        return false;
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/forward-token-comment-cursor.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/forward-token-comment-cursor.js

Statements: 15.79% (3 / 19)      Branches: 0% (0 / 14)      Functions: 0% (0 / 2)      Lines: 15.79% (3 / 19)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59                    1 1                 1                                                                            
/**
 * @fileoverview Define the cursor which iterates tokens and comments.
 * @author Toru Nagashima
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const Cursor = require("./cursor");
const utils = require("./utils");
 
//------------------------------------------------------------------------------
// Exports
//------------------------------------------------------------------------------
 
/**
 * The cursor which iterates tokens and comments.
 */
module.exports = class ForwardTokenCommentCursor extends Cursor {
 
    /**
     * Initializes this cursor.
     * @param {Token[]} tokens - The array of tokens.
     * @param {Comment[]} comments - The array of comments.
     * @param {Object} indexMap - The map from locations to indices in `tokens`.
     * @param {number} startLoc - The start location of the iteration range.
     * @param {number} endLoc - The end location of the iteration range.
     */
    constructor(tokens, comments, indexMap, startLoc, endLoc) {
        super();
        this.tokens = tokens;
        this.comments = comments;
        this.tokenIndex = utils.getFirstIndex(tokens, indexMap, startLoc);
        this.commentIndex = utils.search(comments, startLoc);
        this.border = endLoc;
    }
 
    /** @inheritdoc */
    moveNext() {
        const token = (this.tokenIndex < this.tokens.length) ? this.tokens[this.tokenIndex] : null;
        const comment = (this.commentIndex < this.comments.length) ? this.comments[this.commentIndex] : null;
 
        if (token && (!comment || token.range[0] < comment.range[0])) {
            this.current = token;
            this.tokenIndex += 1;
        } else if (comment) {
            this.current = comment;
            this.commentIndex += 1;
        } else {
            this.current = null;
        }
 
        return Boolean(this.current) && (this.border === -1 || this.current.range[1] <= this.border);
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/forward-token-cursor.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/forward-token-cursor.js

Statements: 21.43% (3 / 14)      Branches: 0% (0 / 4)      Functions: 0% (0 / 4)      Lines: 21.43% (3 / 14)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63                    1 1                 1                                                                                    
/**
 * @fileoverview Define the cursor which iterates tokens only.
 * @author Toru Nagashima
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const Cursor = require("./cursor");
const utils = require("./utils");
 
//------------------------------------------------------------------------------
// Exports
//------------------------------------------------------------------------------
 
/**
 * The cursor which iterates tokens only.
 */
module.exports = class ForwardTokenCursor extends Cursor {
 
    /**
     * Initializes this cursor.
     * @param {Token[]} tokens - The array of tokens.
     * @param {Comment[]} comments - The array of comments.
     * @param {Object} indexMap - The map from locations to indices in `tokens`.
     * @param {number} startLoc - The start location of the iteration range.
     * @param {number} endLoc - The end location of the iteration range.
     */
    constructor(tokens, comments, indexMap, startLoc, endLoc) {
        super();
        this.tokens = tokens;
        this.index = utils.getFirstIndex(tokens, indexMap, startLoc);
        this.indexEnd = utils.getLastIndex(tokens, indexMap, endLoc);
    }
 
    /** @inheritdoc */
    moveNext() {
        if (this.index <= this.indexEnd) {
            this.current = this.tokens[this.index];
            this.index += 1;
            return true;
        }
        return false;
    }
 
    //
    // Shorthand for performance.
    //
 
    /** @inheritdoc */
    getOneToken() {
        return (this.index <= this.indexEnd) ? this.tokens[this.index] : null;
    }
 
    /** @inheritdoc */
    getAllTokens() {
        return this.tokens.slice(this.index, this.indexEnd + 1);
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/index.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/index.js

Statements: 12.5% (11 / 88)      Branches: 0% (0 / 46)      Functions: 0% (0 / 22)      Lines: 12.5% (11 / 88)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606                    1 1 1 1           1                                                                     1                                                                                   1                                                                       1                                                                                                       1                                                 1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   1    
/**
 * @fileoverview Object to handle access and retrieval of tokens.
 * @author Brandon Mills
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const assert = require("assert");
const cursors = require("./cursors");
const ForwardTokenCursor = require("./forward-token-cursor");
const PaddedTokenCursor = require("./padded-token-cursor");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const PUBLIC_METHODS = Object.freeze([
    "getTokenByRangeStart",
 
    "getFirstToken",
    "getLastToken",
    "getTokenBefore",
    "getTokenAfter",
    "getFirstTokenBetween",
    "getLastTokenBetween",
 
    "getFirstTokens",
    "getLastTokens",
    "getTokensBefore",
    "getTokensAfter",
    "getFirstTokensBetween",
    "getLastTokensBetween",
 
    "getTokens",
    "getTokensBetween",
 
    "getTokenOrCommentBefore",
    "getTokenOrCommentAfter"
]);
 
/**
 * Creates the map from locations to indices in `tokens`.
 *
 * The first/last location of tokens is mapped to the index of the token.
 * The first/last location of comments is mapped to the index of the next token of each comment.
 *
 * @param {Token[]} tokens - The array of tokens.
 * @param {Comment[]} comments - The array of comments.
 * @returns {Object} The map from locations to indices in `tokens`.
 * @private
 */
function createIndexMap(tokens, comments) {
    const map = Object.create(null);
    let tokenIndex = 0;
    let commentIndex = 0;
    let nextStart = 0;
    let range = null;
 
    while (tokenIndex < tokens.length || commentIndex < comments.length) {
        nextStart = (commentIndex < comments.length) ? comments[commentIndex].range[0] : Number.MAX_SAFE_INTEGER;
        while (tokenIndex < tokens.length && (range = tokens[tokenIndex].range)[0] < nextStart) {
            map[range[0]] = tokenIndex;
            map[range[1] - 1] = tokenIndex;
            tokenIndex += 1;
        }
 
        nextStart = (tokenIndex < tokens.length) ? tokens[tokenIndex].range[0] : Number.MAX_SAFE_INTEGER;
        while (commentIndex < comments.length && (range = comments[commentIndex].range)[0] < nextStart) {
            map[range[0]] = tokenIndex;
            map[range[1] - 1] = tokenIndex;
            commentIndex += 1;
        }
    }
 
    return map;
}
 
/**
 * Creates the cursor iterates tokens with options.
 *
 * @param {CursorFactory} factory - The cursor factory to initialize cursor.
 * @param {Token[]} tokens - The array of tokens.
 * @param {Comment[]} comments - The array of comments.
 * @param {Object} indexMap - The map from locations to indices in `tokens`.
 * @param {number} startLoc - The start location of the iteration range.
 * @param {number} endLoc - The end location of the iteration range.
 * @param {number|Function|Object} [opts=0] - The option object. If this is a number then it's `opts.skip`. If this is a function then it's `opts.filter`.
 * @param {boolean} [opts.includeComments=false] - The flag to iterate comments as well.
 * @param {Function|null} [opts.filter=null] - The predicate function to choose tokens.
 * @param {number} [opts.skip=0] - The count of tokens the cursor skips.
 * @returns {Cursor} The created cursor.
 * @private
 */
function createCursorWithSkip(factory, tokens, comments, indexMap, startLoc, endLoc, opts) {
    let includeComments = false;
    let skip = 0;
    let filter = null;
 
    if (typeof opts === "number") {
        skip = opts | 0;
    } else if (typeof opts === "function") {
        filter = opts;
    } else if (opts) {
        includeComments = !!opts.includeComments;
        skip = opts.skip | 0;
        filter = opts.filter || null;
    }
    assert(skip >= 0, "options.skip should be zero or a positive integer.");
    assert(!filter || typeof filter === "function", "options.filter should be a function.");
 
    return factory.createCursor(tokens, comments, indexMap, startLoc, endLoc, includeComments, filter, skip, -1);
}
 
/**
 * Creates the cursor iterates tokens with options.
 *
 * @param {CursorFactory} factory - The cursor factory to initialize cursor.
 * @param {Token[]} tokens - The array of tokens.
 * @param {Comment[]} comments - The array of comments.
 * @param {Object} indexMap - The map from locations to indices in `tokens`.
 * @param {number} startLoc - The start location of the iteration range.
 * @param {number} endLoc - The end location of the iteration range.
 * @param {number|Function|Object} [opts=0] - The option object. If this is a number then it's `opts.count`. If this is a function then it's `opts.filter`.
 * @param {boolean} [opts.includeComments] - The flag to iterate comments as well.
 * @param {Function|null} [opts.filter=null] - The predicate function to choose tokens.
 * @param {number} [opts.count=0] - The maximum count of tokens the cursor iterates. Zero is no iteration for backward compatibility.
 * @returns {Cursor} The created cursor.
 * @private
 */
function createCursorWithCount(factory, tokens, comments, indexMap, startLoc, endLoc, opts) {
    let includeComments = false;
    let count = 0;
    let countExists = false;
    let filter = null;
 
    if (typeof opts === "number") {
        count = opts | 0;
        countExists = true;
    } else if (typeof opts === "function") {
        filter = opts;
    } else if (opts) {
        includeComments = !!opts.includeComments;
        count = opts.count | 0;
        countExists = typeof opts.count === "number";
        filter = opts.filter || null;
    }
    assert(count >= 0, "options.count should be zero or a positive integer.");
    assert(!filter || typeof filter === "function", "options.filter should be a function.");
 
    return factory.createCursor(tokens, comments, indexMap, startLoc, endLoc, includeComments, filter, 0, countExists ? count : -1);
}
 
/**
 * Creates the cursor iterates tokens with options.
 * This is overload function of the below.
 *
 * @param {Token[]} tokens - The array of tokens.
 * @param {Comment[]} comments - The array of comments.
 * @param {Object} indexMap - The map from locations to indices in `tokens`.
 * @param {number} startLoc - The start location of the iteration range.
 * @param {number} endLoc - The end location of the iteration range.
 * @param {Function|Object} opts - The option object. If this is a function then it's `opts.filter`.
 * @param {boolean} [opts.includeComments] - The flag to iterate comments as well.
 * @param {Function|null} [opts.filter=null] - The predicate function to choose tokens.
 * @param {number} [opts.count=0] - The maximum count of tokens the cursor iterates. Zero is no iteration for backward compatibility.
 * @returns {Cursor} The created cursor.
 * @private
 */
/**
 * Creates the cursor iterates tokens with options.
 *
 * @param {Token[]} tokens - The array of tokens.
 * @param {Comment[]} comments - The array of comments.
 * @param {Object} indexMap - The map from locations to indices in `tokens`.
 * @param {number} startLoc - The start location of the iteration range.
 * @param {number} endLoc - The end location of the iteration range.
 * @param {number} [beforeCount=0] - The number of tokens before the node to retrieve.
 * @param {boolean} [afterCount=0] - The number of tokens after the node to retrieve.
 * @returns {Cursor} The created cursor.
 * @private
 */
function createCursorWithPadding(tokens, comments, indexMap, startLoc, endLoc, beforeCount, afterCount) {
    if (typeof beforeCount === "undefined" && typeof afterCount === "undefined") {
        return new ForwardTokenCursor(tokens, comments, indexMap, startLoc, endLoc);
    }
    if (typeof beforeCount === "number" || typeof beforeCount === "undefined") {
        return new PaddedTokenCursor(tokens, comments, indexMap, startLoc, endLoc, beforeCount | 0, afterCount | 0);
    }
    return createCursorWithCount(cursors.forward, tokens, comments, indexMap, startLoc, endLoc, beforeCount);
}
 
//------------------------------------------------------------------------------
// Exports
//------------------------------------------------------------------------------
 
/**
 * The token store.
 *
 * This class provides methods to get tokens by locations as fast as possible.
 * The methods are a part of public API, so we should be careful if it changes this class.
 *
 * People can get tokens in O(1) by the hash map which is mapping from the location of tokens/comments to tokens.
 * Also people can get a mix of tokens and comments in O(log k), the k is the number of comments.
 * Assuming that comments to be much fewer than tokens, this does not make hash map from token's locations to comments to reduce memory cost.
 * This uses binary-searching instead for comments.
 */
module.exports = class TokenStore {
 
    /**
     * Initializes this token store.
     *
     * ※ `comments` needs to be cloned for backward compatibility.
     * After this initialization, ESLint removes a shebang's comment from `comments`.
     * However, so far we had been concatenating 'tokens' and 'comments' before,
     * so the shebang's comment had remained in the concatenated array.
     * As a result, both the result of `getTokenOrCommentAfter` and `getTokenOrCommentBefore`
     * methods had included the shebang's comment.
     * And some rules depends on this behavior.
     *
     * @param {Token[]} tokens - The array of tokens.
     * @param {Comment[]} comments - The array of comments.
     */
    constructor(tokens, comments) {
        this.tokens = tokens;
        this.comments = comments.slice(0);
        this.indexMap = createIndexMap(tokens, comments);
    }
 
    //--------------------------------------------------------------------------
    // Gets single token.
    //--------------------------------------------------------------------------
 
    /**
     * Gets the token starting at the specified index.
     * @param {number} offset - Index of the start of the token's range.
     * @param {Object} [options=0] - The option object.
     * @param {boolean} [options.includeComments=false] - The flag to iterate comments as well.
     * @returns {Token|null} The token starting at index, or null if no such token.
     */
    getTokenByRangeStart(offset, options) {
        const includeComments = options && options.includeComments;
        const token = cursors.forward.createBaseCursor(
            this.tokens,
            this.comments,
            this.indexMap,
            offset,
            -1,
            includeComments
        ).getOneToken();
 
        if (token && token.range[0] === offset) {
            return token;
        }
        return null;
    }
 
    /**
     * Gets the first token of the given node.
     * @param {ASTNode} node - The AST node.
     * @param {number|Function|Object} [options=0] - The option object. If this is a number then it's `options.skip`. If this is a function then it's `options.filter`.
     * @param {boolean} [options.includeComments=false] - The flag to iterate comments as well.
     * @param {Function|null} [options.filter=null] - The predicate function to choose tokens.
     * @param {number} [options.skip=0] - The count of tokens the cursor skips.
     * @returns {Token|null} An object representing the token.
     */
    getFirstToken(node, options) {
        return createCursorWithSkip(
            cursors.forward,
            this.tokens,
            this.comments,
            this.indexMap,
            node.range[0],
            node.range[1],
            options
        ).getOneToken();
    }
 
    /**
     * Gets the last token of the given node.
     * @param {ASTNode} node - The AST node.
     * @param {number|Function|Object} [options=0] - The option object. If this is a number then it's `options.skip`. If this is a function then it's `options.filter`.
     * @param {boolean} [options.includeComments=false] - The flag to iterate comments as well.
     * @param {Function|null} [options.filter=null] - The predicate function to choose tokens.
     * @param {number} [options.skip=0] - The count of tokens the cursor skips.
     * @returns {Token|null} An object representing the token.
     */
    getLastToken(node, options) {
        return createCursorWithSkip(
            cursors.backward,
            this.tokens,
            this.comments,
            this.indexMap,
            node.range[0],
            node.range[1],
            options
        ).getOneToken();
    }
 
    /**
     * Gets the token that precedes a given node or token.
     * @param {ASTNode|Token|Comment} node - The AST node or token.
     * @param {number|Function|Object} [options=0] - The option object. If this is a number then it's `options.skip`. If this is a function then it's `options.filter`.
     * @param {boolean} [options.includeComments=false] - The flag to iterate comments as well.
     * @param {Function|null} [options.filter=null] - The predicate function to choose tokens.
     * @param {number} [options.skip=0] - The count of tokens the cursor skips.
     * @returns {Token|null} An object representing the token.
     */
    getTokenBefore(node, options) {
        return createCursorWithSkip(
            cursors.backward,
            this.tokens,
            this.comments,
            this.indexMap,
            -1,
            node.range[0],
            options
        ).getOneToken();
    }
 
    /**
     * Gets the token that follows a given node or token.
     * @param {ASTNode|Token|Comment} node - The AST node or token.
     * @param {number|Function|Object} [options=0] - The option object. If this is a number then it's `options.skip`. If this is a function then it's `options.filter`.
     * @param {boolean} [options.includeComments=false] - The flag to iterate comments as well.
     * @param {Function|null} [options.filter=null] - The predicate function to choose tokens.
     * @param {number} [options.skip=0] - The count of tokens the cursor skips.
     * @returns {Token|null} An object representing the token.
     */
    getTokenAfter(node, options) {
        return createCursorWithSkip(
            cursors.forward,
            this.tokens,
            this.comments,
            this.indexMap,
            node.range[1],
            -1,
            options
        ).getOneToken();
    }
 
    /**
     * Gets the first token between two non-overlapping nodes.
     * @param {ASTNode|Token|Comment} left - Node before the desired token range.
     * @param {ASTNode|Token|Comment} right - Node after the desired token range.
     * @param {number|Function|Object} [options=0] - The option object. If this is a number then it's `options.skip`. If this is a function then it's `options.filter`.
     * @param {boolean} [options.includeComments=false] - The flag to iterate comments as well.
     * @param {Function|null} [options.filter=null] - The predicate function to choose tokens.
     * @param {number} [options.skip=0] - The count of tokens the cursor skips.
     * @returns {Token|null} An object representing the token.
     */
    getFirstTokenBetween(left, right, options) {
        return createCursorWithSkip(
            cursors.forward,
            this.tokens,
            this.comments,
            this.indexMap,
            left.range[1],
            right.range[0],
            options
        ).getOneToken();
    }
 
    /**
     * Gets the last token between two non-overlapping nodes.
     * @param {ASTNode|Token|Comment} left Node before the desired token range.
     * @param {ASTNode|Token|Comment} right Node after the desired token range.
     * @param {number|Function|Object} [options=0] The option object. If this is a number then it's `options.skip`. If this is a function then it's `options.filter`.
     * @param {boolean} [options.includeComments=false] - The flag to iterate comments as well.
     * @param {Function|null} [options.filter=null] - The predicate function to choose tokens.
     * @param {number} [options.skip=0] - The count of tokens the cursor skips.
     * @returns {Token|null} Tokens between left and right.
     */
    getLastTokenBetween(left, right, options) {
        return createCursorWithSkip(
            cursors.backward,
            this.tokens,
            this.comments,
            this.indexMap,
            left.range[1],
            right.range[0],
            options
        ).getOneToken();
    }
 
    /**
     * Gets the token that precedes a given node or token in the token stream.
     * This is defined for backward compatibility. Use `includeComments` option instead.
     * TODO: We have a plan to remove this in a future major version.
     * @param {ASTNode|Token|Comment} node The AST node or token.
     * @param {number} [skip=0] A number of tokens to skip.
     * @returns {Token|null} An object representing the token.
     * @deprecated
     */
    getTokenOrCommentBefore(node, skip) {
        return this.getTokenBefore(node, { includeComments: true, skip });
    }
 
    /**
     * Gets the token that follows a given node or token in the token stream.
     * This is defined for backward compatibility. Use `includeComments` option instead.
     * TODO: We have a plan to remove this in a future major version.
     * @param {ASTNode|Token|Comment} node The AST node or token.
     * @param {number} [skip=0] A number of tokens to skip.
     * @returns {Token|null} An object representing the token.
     * @deprecated
     */
    getTokenOrCommentAfter(node, skip) {
        return this.getTokenAfter(node, { includeComments: true, skip });
    }
 
    //--------------------------------------------------------------------------
    // Gets multiple tokens.
    //--------------------------------------------------------------------------
 
    /**
     * Gets the first `count` tokens of the given node.
     * @param {ASTNode} node - The AST node.
     * @param {number|Function|Object} [options=0] - The option object. If this is a number then it's `options.count`. If this is a function then it's `options.filter`.
     * @param {boolean} [options.includeComments=false] - The flag to iterate comments as well.
     * @param {Function|null} [options.filter=null] - The predicate function to choose tokens.
     * @param {number} [options.count=0] - The maximum count of tokens the cursor iterates.
     * @returns {Token[]} Tokens.
     */
    getFirstTokens(node, options) {
        return createCursorWithCount(
            cursors.forward,
            this.tokens,
            this.comments,
            this.indexMap,
            node.range[0],
            node.range[1],
            options
        ).getAllTokens();
    }
 
    /**
     * Gets the last `count` tokens of the given node.
     * @param {ASTNode} node - The AST node.
     * @param {number|Function|Object} [options=0] - The option object. If this is a number then it's `options.count`. If this is a function then it's `options.filter`.
     * @param {boolean} [options.includeComments=false] - The flag to iterate comments as well.
     * @param {Function|null} [options.filter=null] - The predicate function to choose tokens.
     * @param {number} [options.count=0] - The maximum count of tokens the cursor iterates.
     * @returns {Token[]} Tokens.
     */
    getLastTokens(node, options) {
        return createCursorWithCount(
            cursors.backward,
            this.tokens,
            this.comments,
            this.indexMap,
            node.range[0],
            node.range[1],
            options
        ).getAllTokens().reverse();
    }
 
    /**
     * Gets the `count` tokens that precedes a given node or token.
     * @param {ASTNode|Token|Comment} node - The AST node or token.
     * @param {number|Function|Object} [options=0] - The option object. If this is a number then it's `options.count`. If this is a function then it's `options.filter`.
     * @param {boolean} [options.includeComments=false] - The flag to iterate comments as well.
     * @param {Function|null} [options.filter=null] - The predicate function to choose tokens.
     * @param {number} [options.count=0] - The maximum count of tokens the cursor iterates.
     * @returns {Token[]} Tokens.
     */
    getTokensBefore(node, options) {
        return createCursorWithCount(
            cursors.backward,
            this.tokens,
            this.comments,
            this.indexMap,
            -1,
            node.range[0],
            options
        ).getAllTokens().reverse();
    }
 
    /**
     * Gets the `count` tokens that follows a given node or token.
     * @param {ASTNode|Token|Comment} node - The AST node or token.
     * @param {number|Function|Object} [options=0] - The option object. If this is a number then it's `options.count`. If this is a function then it's `options.filter`.
     * @param {boolean} [options.includeComments=false] - The flag to iterate comments as well.
     * @param {Function|null} [options.filter=null] - The predicate function to choose tokens.
     * @param {number} [options.count=0] - The maximum count of tokens the cursor iterates.
     * @returns {Token[]} Tokens.
     */
    getTokensAfter(node, options) {
        return createCursorWithCount(
            cursors.forward,
            this.tokens,
            this.comments,
            this.indexMap,
            node.range[1],
            -1,
            options
        ).getAllTokens();
    }
 
    /**
     * Gets the first `count` tokens between two non-overlapping nodes.
     * @param {ASTNode|Token|Comment} left - Node before the desired token range.
     * @param {ASTNode|Token|Comment} right - Node after the desired token range.
     * @param {number|Function|Object} [options=0] - The option object. If this is a number then it's `options.count`. If this is a function then it's `options.filter`.
     * @param {boolean} [options.includeComments=false] - The flag to iterate comments as well.
     * @param {Function|null} [options.filter=null] - The predicate function to choose tokens.
     * @param {number} [options.count=0] - The maximum count of tokens the cursor iterates.
     * @returns {Token[]} Tokens between left and right.
     */
    getFirstTokensBetween(left, right, options) {
        return createCursorWithCount(
            cursors.forward,
            this.tokens,
            this.comments,
            this.indexMap,
            left.range[1],
            right.range[0],
            options
        ).getAllTokens();
    }
 
    /**
     * Gets the last `count` tokens between two non-overlapping nodes.
     * @param {ASTNode|Token|Comment} left Node before the desired token range.
     * @param {ASTNode|Token|Comment} right Node after the desired token range.
     * @param {number|Function|Object} [options=0] The option object. If this is a number then it's `options.count`. If this is a function then it's `options.filter`.
     * @param {boolean} [options.includeComments=false] - The flag to iterate comments as well.
     * @param {Function|null} [options.filter=null] - The predicate function to choose tokens.
     * @param {number} [options.count=0] - The maximum count of tokens the cursor iterates.
     * @returns {Token[]} Tokens between left and right.
     */
    getLastTokensBetween(left, right, options) {
        return createCursorWithCount(
            cursors.backward,
            this.tokens,
            this.comments,
            this.indexMap,
            left.range[1],
            right.range[0],
            options
        ).getAllTokens().reverse();
    }
 
    /**
     * Gets all tokens that are related to the given node.
     * @param {ASTNode} node - The AST node.
     * @param {Function|Object} options The option object. If this is a function then it's `options.filter`.
     * @param {boolean} [options.includeComments=false] - The flag to iterate comments as well.
     * @param {Function|null} [options.filter=null] - The predicate function to choose tokens.
     * @param {number} [options.count=0] - The maximum count of tokens the cursor iterates.
     * @returns {Token[]} Array of objects representing tokens.
     */
    /**
     * Gets all tokens that are related to the given node.
     * @param {ASTNode} node - The AST node.
     * @param {int} [beforeCount=0] - The number of tokens before the node to retrieve.
     * @param {int} [afterCount=0] - The number of tokens after the node to retrieve.
     * @returns {Token[]} Array of objects representing tokens.
     */
    getTokens(node, beforeCount, afterCount) {
        return createCursorWithPadding(
            this.tokens,
            this.comments,
            this.indexMap,
            node.range[0],
            node.range[1],
            beforeCount,
            afterCount
        ).getAllTokens();
    }
 
    /**
     * Gets all of the tokens between two non-overlapping nodes.
     * @param {ASTNode|Token|Comment} left Node before the desired token range.
     * @param {ASTNode|Token|Comment} right Node after the desired token range.
     * @param {Function|Object} options The option object. If this is a function then it's `options.filter`.
     * @param {boolean} [options.includeComments=false] - The flag to iterate comments as well.
     * @param {Function|null} [options.filter=null] - The predicate function to choose tokens.
     * @param {number} [options.count=0] - The maximum count of tokens the cursor iterates.
     * @returns {Token[]} Tokens between left and right.
     */
    /**
     * Gets all of the tokens between two non-overlapping nodes.
     * @param {ASTNode|Token|Comment} left Node before the desired token range.
     * @param {ASTNode|Token|Comment} right Node after the desired token range.
     * @param {int} [padding=0] Number of extra tokens on either side of center.
     * @returns {Token[]} Tokens between left and right.
     */
    getTokensBetween(left, right, padding) {
        return createCursorWithPadding(
            this.tokens,
            this.comments,
            this.indexMap,
            left.range[1],
            right.range[0],
            padding,
            padding
        ).getAllTokens();
    }
};
 
module.exports.PUBLIC_METHODS = PUBLIC_METHODS;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/limit-cursor.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/limit-cursor.js

Statements: 25% (2 / 8)      Branches: 0% (0 / 2)      Functions: 0% (0 / 2)      Lines: 25% (2 / 8)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42                    1                 1                                            
/**
 * @fileoverview Define the cursor which limits the number of tokens.
 * @author Toru Nagashima
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const DecorativeCursor = require("./decorative-cursor");
 
//------------------------------------------------------------------------------
// Exports
//------------------------------------------------------------------------------
 
/**
 * The decorative cursor which limits the number of tokens.
 */
module.exports = class LimitCursor extends DecorativeCursor {
 
    /**
     * Initializes this cursor.
     * @param {Cursor} cursor - The cursor to be decorated.
     * @param {number} count - The count of tokens this cursor iterates.
     */
    constructor(cursor, count) {
        super(cursor);
        this.count = count;
    }
 
    /** @inheritdoc */
    moveNext() {
        if (this.count > 0) {
            this.count -= 1;
            return super.moveNext();
        }
        return false;
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/padded-token-cursor.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/padded-token-cursor.js

Statements: 40% (2 / 5)      Branches: 100% (0 / 0)      Functions: 0% (0 / 1)      Lines: 40% (2 / 5)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40                    1                   1                                      
/**
 * @fileoverview Define the cursor which iterates tokens only, with inflated range.
 * @author Toru Nagashima
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const ForwardTokenCursor = require("./forward-token-cursor");
 
//------------------------------------------------------------------------------
// Exports
//------------------------------------------------------------------------------
 
/**
 * The cursor which iterates tokens only, with inflated range.
 * This is for the backward compatibility of padding options.
 */
module.exports = class PaddedTokenCursor extends ForwardTokenCursor {
 
    /**
     * Initializes this cursor.
     * @param {Token[]} tokens - The array of tokens.
     * @param {Comment[]} comments - The array of comments.
     * @param {Object} indexMap - The map from locations to indices in `tokens`.
     * @param {number} startLoc - The start location of the iteration range.
     * @param {number} endLoc - The end location of the iteration range.
     * @param {number} beforeCount - The number of tokens this cursor iterates before start.
     * @param {number} afterCount - The number of tokens this cursor iterates after end.
     */
    constructor(tokens, comments, indexMap, startLoc, endLoc, beforeCount, afterCount) {
        super(tokens, comments, indexMap, startLoc, endLoc);
        this.index = Math.max(0, this.index - beforeCount);
        this.indexEnd = Math.min(tokens.length - 1, this.indexEnd + afterCount);
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/skip-cursor.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/skip-cursor.js

Statements: 22.22% (2 / 9)      Branches: 0% (0 / 2)      Functions: 0% (0 / 2)      Lines: 22.22% (2 / 9)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44                    1                 1                                                
/**
 * @fileoverview Define the cursor which ignores the first few tokens.
 * @author Toru Nagashima
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const DecorativeCursor = require("./decorative-cursor");
 
//------------------------------------------------------------------------------
// Exports
//------------------------------------------------------------------------------
 
/**
 * The decorative cursor which ignores the first few tokens.
 */
module.exports = class SkipCursor extends DecorativeCursor {
 
    /**
     * Initializes this cursor.
     * @param {Cursor} cursor - The cursor to be decorated.
     * @param {number} count - The count of tokens this cursor skips.
     */
    constructor(cursor, count) {
        super(cursor);
        this.count = count;
    }
 
    /** @inheritdoc */
    moveNext() {
        while (this.count > 0) {
            this.count -= 1;
            if (!super.moveNext()) {
                return false;
            }
        }
        return super.moveNext();
    }
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/utils.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/token-store/utils.js

Statements: 20% (5 / 25)      Branches: 0% (0 / 24)      Functions: 0% (0 / 4)      Lines: 20% (5 / 25)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102                    1                         1                               1                                 1                                                     1                                    
/**
 * @fileoverview Define utilify functions for token store.
 * @author Toru Nagashima
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const lodash = require("lodash");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Gets `token.range[0]` from the given token.
 *
 * @param {Node|Token|Comment} token - The token to get.
 * @returns {number} The start location.
 * @private
 */
function getStartLocation(token) {
    return token.range[0];
}
 
//------------------------------------------------------------------------------
// Exports
//------------------------------------------------------------------------------
 
/**
 * Binary-searches the index of the first token which is after the given location.
 * If it was not found, this returns `tokens.length`.
 *
 * @param {(Token|Comment)[]} tokens - It searches the token in this list.
 * @param {number} location - The location to search.
 * @returns {number} The found index or `tokens.length`.
 */
exports.search = function search(tokens, location) {
    return lodash.sortedIndexBy(
        tokens,
        { range: [location] },
        getStartLocation
    );
};
 
/**
 * Gets the index of the `startLoc` in `tokens`.
 * `startLoc` can be the value of `node.range[1]`, so this checks about `startLoc - 1` as well.
 *
 * @param {(Token|Comment)[]} tokens - The tokens to find an index.
 * @param {Object} indexMap - The map from locations to indices.
 * @param {number} startLoc - The location to get an index.
 * @returns {number} The index.
 */
exports.getFirstIndex = function getFirstIndex(tokens, indexMap, startLoc) {
    if (startLoc in indexMap) {
        return indexMap[startLoc];
    }
    if ((startLoc - 1) in indexMap) {
        const index = indexMap[startLoc - 1];
        const token = (index >= 0 && index < tokens.length) ? tokens[index] : null;
 
        // For the map of "comment's location -> token's index", it points the next token of a comment.
        // In that case, +1 is unnecessary.
        if (token && token.range[0] >= startLoc) {
            return index;
        }
        return index + 1;
    }
    return 0;
};
 
/**
 * Gets the index of the `endLoc` in `tokens`.
 * The information of end locations are recorded at `endLoc - 1` in `indexMap`, so this checks about `endLoc - 1` as well.
 *
 * @param {(Token|Comment)[]} tokens - The tokens to find an index.
 * @param {Object} indexMap - The map from locations to indices.
 * @param {number} endLoc - The location to get an index.
 * @returns {number} The index.
 */
exports.getLastIndex = function getLastIndex(tokens, indexMap, endLoc) {
    if (endLoc in indexMap) {
        return indexMap[endLoc] - 1;
    }
    if ((endLoc - 1) in indexMap) {
        const index = indexMap[endLoc - 1];
        const token = (index >= 0 && index < tokens.length) ? tokens[index] : null;
 
        // For the map of "comment's location -> token's index", it points the next token of a comment.
        // In that case, -1 is necessary.
        if (token && token.range[1] > endLoc) {
            return index - 1;
        }
        return index;
    }
    return tokens.length - 1;
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/

Statements: 15.98% (62 / 388)      Branches: 1.2% (3 / 249)      Functions: 1.52% (1 / 66)      Lines: 16.36% (62 / 379)      Ignored: none     

All files » node-npmtest-eslint/node_modules/eslint/lib/util/
File Statements Branches Functions Lines
comment-event-generator.js 15.38% (4 / 26) 0% (0 / 4) 0% (0 / 6) 15.38% (4 / 26)
fix-tracker.js 11.11% (2 / 18) 0% (0 / 8) 0% (0 / 6) 11.11% (2 / 18)
glob-util.js 12.5% (7 / 56) 0% (0 / 35) 0% (0 / 5) 12.96% (7 / 54)
glob.js 50% (6 / 12) 0% (0 / 2) 0% (0 / 2) 50% (6 / 12)
hash.js 75% (3 / 4) 100% (0 / 0) 0% (0 / 1) 75% (3 / 4)
keywords.js 100% (1 / 1) 100% (0 / 0) 100% (0 / 0) 100% (1 / 1)
module-resolver.js 40% (4 / 10) 50% (3 / 6) 50% (1 / 2) 40% (4 / 10)
node-event-generator.js 11.25% (9 / 80) 0% (0 / 67) 0% (0 / 10) 12.16% (9 / 74)
path-util.js 25% (4 / 16) 0% (0 / 6) 0% (0 / 2) 25% (4 / 16)
rule-fixer.js 25% (3 / 12) 100% (0 / 0) 0% (0 / 9) 25% (3 / 12)
source-code-fixer.js 18.42% (7 / 38) 0% (0 / 22) 0% (0 / 4) 18.42% (7 / 38)
source-code.js 8.33% (9 / 108) 0% (0 / 99) 0% (0 / 17) 8.33% (9 / 108)
traverser.js 42.86% (3 / 7) 100% (0 / 0) 0% (0 / 2) 50% (3 / 6)
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/comment-event-generator.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/comment-event-generator.js

Statements: 15.38% (4 / 26)      Branches: 0% (0 / 4)      Functions: 0% (0 / 6)      Lines: 15.38% (4 / 26)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118                                        1                                         1                           1                                                                                                                       1    
/**
 * @fileoverview The event generator for comments.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Check collection of comments to prevent double event for comment as
 * leading and trailing, then emit event if passing
 * @param {ASTNode[]} comments - Collection of comment nodes
 * @param {EventEmitter} emitter - The event emitter which is the destination of events.
 * @param {Object[]} locs - List of locations of previous comment nodes
 * @param {string} eventName - Event name postfix
 * @returns {void}
 */
function emitComments(comments, emitter, locs, eventName) {
    if (comments.length > 0) {
        comments.forEach(node => {
            const index = locs.indexOf(node.loc);
 
            if (index >= 0) {
                locs.splice(index, 1);
            } else {
                locs.push(node.loc);
                emitter.emit(node.type + eventName, node);
            }
        });
    }
}
 
/**
 * Shortcut to check and emit enter of comment nodes
 * @param {CommentEventGenerator} generator - A generator to emit.
 * @param {ASTNode[]} comments - Collection of comment nodes
 * @returns {void}
 */
function emitCommentsEnter(generator, comments) {
    emitComments(
        comments,
        generator.emitter,
        generator.commentLocsEnter,
        "Comment");
}
 
/**
 * Shortcut to check and emit exit of comment nodes
 * @param {CommentEventGenerator} generator - A generator to emit.
 * @param {ASTNode[]} comments Collection of comment nodes
 * @returns {void}
 */
function emitCommentsExit(generator, comments) {
    emitComments(
        comments,
        generator.emitter,
        generator.commentLocsExit,
        "Comment:exit");
}
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
/**
 * The event generator for comments.
 * This is the decorator pattern.
 * This generates events of comments before/after events which are generated the original generator.
 *
 * Comment event generator class
 */
class CommentEventGenerator {
 
    /**
     * @param {EventGenerator} originalEventGenerator - An event generator which is the decoration target.
     * @param {SourceCode} sourceCode - A source code which has comments.
     */
    constructor(originalEventGenerator, sourceCode) {
        this.original = originalEventGenerator;
        this.emitter = originalEventGenerator.emitter;
        this.sourceCode = sourceCode;
        this.commentLocsEnter = [];
        this.commentLocsExit = [];
    }
 
    /**
     * Emits an event of entering comments.
     * @param {ASTNode} node - A node which was entered.
     * @returns {void}
     */
    enterNode(node) {
        const comments = this.sourceCode.getComments(node);
 
        emitCommentsEnter(this, comments.leading);
        this.original.enterNode(node);
        emitCommentsEnter(this, comments.trailing);
    }
 
    /**
     * Emits an event of leaving comments.
     * @param {ASTNode} node - A node which was left.
     * @returns {void}
     */
    leaveNode(node) {
        const comments = this.sourceCode.getComments(node);
 
        emitCommentsExit(this, comments.trailing);
        this.original.leaveNode(node);
        emitCommentsExit(this, comments.leading);
    }
}
 
module.exports = CommentEventGenerator;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/fix-tracker.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/fix-tracker.js

Statements: 11.11% (2 / 18)      Branches: 0% (0 / 8)      Functions: 0% (0 / 6)      Lines: 11.11% (2 / 18)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123                    1                                                                                                                                                                                                                           1    
/**
 * @fileoverview Helper class to aid in constructing fix commands.
 * @author Alan Pierce
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const astUtils = require("../ast-utils");
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
/**
 * A helper class to combine fix options into a fix command. Currently, it
 * exposes some "retain" methods that extend the range of the text being
 * replaced so that other fixes won't touch that region in the same pass.
 */
class FixTracker {
 
    /**
     * Create a new FixTracker.
     *
     * @param {ruleFixer} fixer A ruleFixer instance.
     * @param {SourceCode} sourceCode A SourceCode object for the current code.
     */
    constructor(fixer, sourceCode) {
        this.fixer = fixer;
        this.sourceCode = sourceCode;
        this.retainedRange = null;
    }
 
    /**
     * Mark the given range as "retained", meaning that other fixes may not
     * may not modify this region in the same pass.
     *
     * @param {int[]} range The range to retain.
     * @returns {FixTracker} The same RuleFixer, for chained calls.
     */
    retainRange(range) {
        this.retainedRange = range;
        return this;
    }
 
    /**
     * Given a node, find the function containing it (or the entire program) and
     * mark it as retained, meaning that other fixes may not modify it in this
     * pass. This is useful for avoiding conflicts in fixes that modify control
     * flow.
     *
     * @param {ASTNode} node The node to use as a starting point.
     * @returns {FixTracker} The same RuleFixer, for chained calls.
     */
    retainEnclosingFunction(node) {
        const functionNode = astUtils.getUpperFunction(node);
 
        return this.retainRange(
            functionNode ? functionNode.range : this.sourceCode.ast.range);
    }
 
    /**
     * Given a node or token, find the token before and afterward, and mark that
     * range as retained, meaning that other fixes may not modify it in this
     * pass. This is useful for avoiding conflicts in fixes that make a small
     * change to the code where the AST should not be changed.
     *
     * @param {ASTNode|Token} nodeOrToken The node or token to use as a starting
     *      point. The token to the left and right are use in the range.
     * @returns {FixTracker} The same RuleFixer, for chained calls.
     */
    retainSurroundingTokens(nodeOrToken) {
        const tokenBefore = this.sourceCode.getTokenBefore(nodeOrToken) || nodeOrToken;
        const tokenAfter = this.sourceCode.getTokenAfter(nodeOrToken) || nodeOrToken;
 
        return this.retainRange([tokenBefore.range[0], tokenAfter.range[1]]);
    }
 
    /**
     * Create a fix command that replaces the given range with the given text,
     * accounting for any retained ranges.
     *
     * @param {int[]} range The range to remove in the fix.
     * @param {string} text The text to insert in place of the range.
     * @returns {Object} The fix command.
     */
    replaceTextRange(range, text) {
        let actualRange;
 
        if (this.retainedRange) {
            actualRange = [
                Math.min(this.retainedRange[0], range[0]),
                Math.max(this.retainedRange[1], range[1])
            ];
        } else {
            actualRange = range;
        }
 
        return this.fixer.replaceTextRange(
            actualRange,
            this.sourceCode.text.slice(actualRange[0], range[0]) +
                text +
                this.sourceCode.text.slice(range[1], actualRange[1])
        );
    }
 
    /**
     * Create a fix command that removes the given node or token, accounting for
     * any retained ranges.
     *
     * @param {ASTNode|Token} nodeOrToken The node or token to remove.
     * @returns {Object} The fix command.
     */
    remove(nodeOrToken) {
        return this.replaceTextRange(nodeOrToken.range, "");
    }
}
 
module.exports = FixTracker;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/glob-util.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/glob-util.js

Statements: 12.5% (7 / 56)      Branches: 0% (0 / 35)      Functions: 0% (0 / 5)      Lines: 12.96% (7 / 54)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185                    1               1                                             1                                                                                     1                                     1                               1                                                                                                                       1          
/**
 * @fileoverview Utilities for working with globs and the filesystem.
 * @author Ian VanSchooten
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const fs = require("fs"),
    path = require("path"),
    GlobSync = require("./glob"),
    shell = require("shelljs"),
 
    pathUtil = require("./path-util"),
    IgnoredPaths = require("../ignored-paths");
 
const debug = require("debug")("eslint:glob-util");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Checks if a provided path is a directory and returns a glob string matching
 * all files under that directory if so, the path itself otherwise.
 *
 * Reason for this is that `glob` needs `/**` to collect all the files under a
 * directory where as our previous implementation without `glob` simply walked
 * a directory that is passed. So this is to maintain backwards compatibility.
 *
 * Also makes sure all path separators are POSIX style for `glob` compatibility.
 *
 * @param {Object}   [options]                    An options object
 * @param {string[]} [options.extensions=[".js"]] An array of accepted extensions
 * @param {string}   [options.cwd=process.cwd()]  The cwd to use to resolve relative pathnames
 * @returns {Function} A function that takes a pathname and returns a glob that
 *                     matches all files with the provided extensions if
 *                     pathname is a directory.
 */
function processPath(options) {
    const cwd = (options && options.cwd) || process.cwd();
    let extensions = (options && options.extensions) || [".js"];
 
    extensions = extensions.map(ext => ext.replace(/^\./, ""));
 
    let suffix = "/**";
 
    if (extensions.length === 1) {
        suffix += `/*.${extensions[0]}`;
    } else {
        suffix += `/*.{${extensions.join(",")}}`;
    }
 
    /**
     * A function that converts a directory name to a glob pattern
     *
     * @param {string} pathname The directory path to be modified
     * @returns {string} The glob path or the file path itself
     * @private
     */
    return function(pathname) {
        let newPath = pathname;
        const resolvedPath = path.resolve(cwd, pathname);
 
        if (shell.test("-d", resolvedPath)) {
            newPath = pathname.replace(/[/\\]$/, "") + suffix;
        }
 
        return pathUtil.convertPathToPosix(newPath);
    };
}
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
/**
 * Resolves any directory patterns into glob-based patterns for easier handling.
 * @param   {string[]} patterns    File patterns (such as passed on the command line).
 * @param   {Object} options       An options object.
 * @returns {string[]} The equivalent glob patterns and filepath strings.
 */
function resolveFileGlobPatterns(patterns, options) {
 
    const processPathExtensions = processPath(options);
 
    return patterns.filter(p => p.length).map(processPathExtensions);
}
 
/**
 * Build a list of absolute filesnames on which ESLint will act.
 * Ignored files are excluded from the results, as are duplicates.
 *
 * @param   {string[]} globPatterns            Glob patterns.
 * @param   {Object}   [options]               An options object.
 * @param   {string}   [options.cwd]           CWD (considered for relative filenames)
 * @param   {boolean}  [options.ignore]        False disables use of .eslintignore.
 * @param   {string}   [options.ignorePath]    The ignore file to use instead of .eslintignore.
 * @param   {string}   [options.ignorePattern] A pattern of files to ignore.
 * @returns {string[]} Resolved absolute filenames.
 */
function listFilesToProcess(globPatterns, options) {
    options = options || { ignore: true };
    const files = [],
        added = {};
 
    const cwd = (options && options.cwd) || process.cwd();
 
    /**
     * Executes the linter on a file defined by the `filename`. Skips
     * unsupported file extensions and any files that are already linted.
     * @param {string} filename The file to be processed
     * @param {boolean} shouldWarnIgnored Whether or not a report should be made if
     *                                    the file is ignored
     * @param {IgnoredPaths} ignoredPaths An instance of IgnoredPaths
     * @returns {void}
     */
    function addFile(filename, shouldWarnIgnored, ignoredPaths) {
        let ignored = false;
        let isSilentlyIgnored;
 
        if (ignoredPaths.contains(filename, "default")) {
            ignored = (options.ignore !== false) && shouldWarnIgnored;
            isSilentlyIgnored = !shouldWarnIgnored;
        }
 
        if (options.ignore !== false) {
            if (ignoredPaths.contains(filename, "custom")) {
                if (shouldWarnIgnored) {
                    ignored = true;
                } else {
                    isSilentlyIgnored = true;
                }
            }
        }
 
        if (isSilentlyIgnored && !ignored) {
            return;
        }
 
        if (added[filename]) {
            return;
        }
        files.push({ filename, ignored });
        added[filename] = true;
    }
 
    debug("Creating list of files to process.");
    globPatterns.forEach(pattern => {
        const file = path.resolve(cwd, pattern);
 
        if (shell.test("-f", file)) {
            const ignoredPaths = new IgnoredPaths(options);
 
            addFile(fs.realpathSync(file), !shell.test("-d", file), ignoredPaths);
        } else {
 
            // regex to find .hidden or /.hidden patterns, but not ./relative or ../relative
            const globIncludesDotfiles = /(?:(?:^\.)|(?:[/\\]\.))[^/\\.].*/.test(pattern);
 
            const ignoredPaths = new IgnoredPaths(Object.assign({}, options, { dotfiles: options.dotfiles || globIncludesDotfiles }));
            const shouldIgnore = ignoredPaths.getIgnoredFoldersGlobChecker();
            const globOptions = {
                nodir: true,
                dot: true,
                cwd
            };
 
            new GlobSync(pattern, globOptions, shouldIgnore).found.forEach(globMatch => {
                addFile(path.resolve(cwd, globMatch), false, ignoredPaths);
            });
        }
    });
 
    return files;
}
 
module.exports = {
    resolveFileGlobPatterns,
    listFilesToProcess
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/glob.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/glob.js

Statements: 50% (6 / 12)      Branches: 0% (0 / 2)      Functions: 0% (0 / 2)      Lines: 50% (6 / 12)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65                    1             1                 1                         1       1                                     1    
/**
 * @fileoverview An inherited `glob.GlobSync` to support .gitignore patterns.
 * @author Kael Zhang
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const Sync = require("glob").GlobSync,
    util = require("util");
 
//------------------------------------------------------------------------------
// Private
//------------------------------------------------------------------------------
 
const IGNORE = Symbol("ignore");
 
/**
 * Subclass of `glob.GlobSync`
 * @param {string}     pattern      Pattern to be matched.
 * @param {Object}     options      `options` for `glob`
 * @param {function()} shouldIgnore Method to check whether a directory should be ignored.
 * @constructor
 */
function GlobSync(pattern, options, shouldIgnore) {
 
    /**
     * We don't put this thing to argument `options` to avoid
     * further problems, such as `options` validation.
     *
     * Use `Symbol` as much as possible to avoid confliction.
     */
    this[IGNORE] = shouldIgnore;
 
    Sync.call(this, pattern, options);
}
 
util.inherits(GlobSync, Sync);
 
/* eslint no-underscore-dangle: ["error", { "allow": ["_readdir", "_mark"] }] */
 
GlobSync.prototype._readdir = function(abs, inGlobStar) {
 
    /**
     * `options.nodir` makes `options.mark` as `true`.
     * Mark `abs` first
     * to make sure `"node_modules"` will be ignored immediately with ignore pattern `"node_modules/"`.
 
     * There is a built-in cache about marked `File.Stat` in `glob`, so that we could not worry about the extra invocation of `this._mark()`
     */
    const marked = this._mark(abs);
 
    if (this[IGNORE](marked)) {
        return null;
    }
 
    return Sync.prototype._readdir.call(this, abs, inGlobStar);
};
 
 
module.exports = GlobSync;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/hash.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/hash.js

Statements: 75% (3 / 4)      Branches: 100% (0 / 0)      Functions: 0% (0 / 1)      Lines: 75% (3 / 4)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37                      1                             1               1    
/**
 * @fileoverview Defining the hashing function in one place.
 * @author Michael Ficarra
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const murmur = require("imurmurhash");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
//------------------------------------------------------------------------------
// Private
//------------------------------------------------------------------------------
 
/**
 * hash the given string
 * @param  {string} str the string to hash
 * @returns {string}    the hash
 */
function hash(str) {
    return murmur(str).result().toString(36);
}
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
module.exports = hash;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/keywords.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/keywords.js

Statements: 100% (1 / 1)      Branches: 100% (0 / 0)      Functions: 100% (0 / 0)      Lines: 100% (1 / 1)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69            1                                                                                                                            
/**
 * @fileoverview A shared list of ES3 keywords.
 * @author Josh Perez
 */
"use strict";
 
module.exports = [
    "abstract",
    "boolean",
    "break",
    "byte",
    "case",
    "catch",
    "char",
    "class",
    "const",
    "continue",
    "debugger",
    "default",
    "delete",
    "do",
    "double",
    "else",
    "enum",
    "export",
    "extends",
    "false",
    "final",
    "finally",
    "float",
    "for",
    "function",
    "goto",
    "if",
    "implements",
    "import",
    "in",
    "instanceof",
    "int",
    "interface",
    "long",
    "native",
    "new",
    "null",
    "package",
    "private",
    "protected",
    "public",
    "return",
    "short",
    "static",
    "super",
    "switch",
    "synchronized",
    "this",
    "throw",
    "throws",
    "transient",
    "true",
    "try",
    "typeof",
    "var",
    "void",
    "volatile",
    "while",
    "with"
];
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/module-resolver.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/module-resolver.js

Statements: 40% (4 / 10)      Branches: 50% (3 / 6)      Functions: 50% (1 / 2)      Lines: 40% (4 / 10)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87                      1           1                                                 1                                                                                   1    
/**
 * @fileoverview Implements the Node.js require.resolve algorithm
 * @author Nicholas C. Zakas
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const Module = require("module");
 
//------------------------------------------------------------------------------
// Private
//------------------------------------------------------------------------------
 
const DEFAULT_OPTIONS = {
 
    /*
     * module.paths is an array of paths to search for resolving things relative
     * to this file. Module.globalPaths contains all of the special Node.js
     * directories that can also be searched for modules.
     *
     * Need to check for existence of module.paths because Jest seems not to
     * include it. See https://github.com/eslint/eslint/issues/5791.
     */
    lookupPaths: module.paths ? module.paths.concat(Module.globalPaths) : Module.globalPaths.concat()
};
 
/**
 * Resolves modules based on a set of options.
 */
class ModuleResolver {
 
    /**
     * Resolves modules based on a set of options.
     * @param {Object} options The options for resolving modules.
     * @param {string[]} options.lookupPaths An array of paths to include in the
     *      lookup with the highest priority paths coming first.
     */
    constructor(options) {
        this.options = Object.assign({}, DEFAULT_OPTIONS, options || {});
    }
 
    /**
     * Resolves the file location of a given module relative to the configured
     * lookup paths.
     * @param {string} name The module name to resolve.
     * @param {string} extraLookupPath An extra path to look into for the module.
     *      This path is used with the highest priority.
     * @returns {string} The resolved file path for the module.
     * @throws {Error} If the module cannot be resolved.
     */
    resolve(name, extraLookupPath) {
 
        /*
         * First, clone the lookup paths so we're not messing things up for
         * subsequent calls to this function. Then, move the extraLookupPath to the
         * top of the lookup paths list so it will be searched first.
         */
        const lookupPaths = this.options.lookupPaths.concat();
 
        lookupPaths.unshift(extraLookupPath);
 
        /**
         * Module._findPath is an internal method to Node.js, then one they use to
         * lookup file paths when require() is called. So, we are hooking into the
         * exact same logic that Node.js uses.
         */
        const result = Module._findPath(name, lookupPaths);   // eslint-disable-line no-underscore-dangle
 
        if (!result) {
            throw new Error(`Cannot find module '${name}'`);
        }
 
        return result;
    }
}
 
//------------------------------------------------------------------------------
// Public API
//------------------------------------------------------------------------------
 
module.exports = ModuleResolver;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/node-event-generator.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/node-event-generator.js

Statements: 11.25% (9 / 80)      Branches: 0% (0 / 67)      Functions: 0% (0 / 10)      Lines: 12.16% (9 / 74)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324                      1 1                                                     1                                                                                           1                                                         1                                                             1                       1                               1                                                                                                                                                                                                                                                                                                       1    
/**
 * @fileoverview The event generator for AST nodes.
 * @author Toru Nagashima
 */
 
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const esquery = require("esquery");
const lodash = require("lodash");
 
//------------------------------------------------------------------------------
// Typedefs
//------------------------------------------------------------------------------
 
/**
 * An object describing an AST selector
 * @typedef {Object} ASTSelector
 * @property {string} rawSelector The string that was parsed into this selector
 * @property {boolean} isExit `true` if this should be emitted when exiting the node rather than when entering
 * @property {Object} parsedSelector An object (from esquery) describing the matching behavior of the selector
 * @property {string[]|null} listenerTypes A list of node types that could possibly cause the selector to match,
 * or `null` if all node types could cause a match
 * @property {number} attributeCount The total number of classes, pseudo-classes, and attribute queries in this selector
 * @property {number} identifierCount The total number of identifier queries in this selector
 */
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
* Gets the possible types of a selector
* @param {Object} parsedSelector An object (from esquery) describing the matching behavior of the selector
* @returns {string[]|null} The node types that could possibly trigger this selector, or `null` if all node types could trigger it
*/
function getPossibleTypes(parsedSelector) {
    switch (parsedSelector.type) {
        case "identifier":
            return [parsedSelector.value];
 
        case "matches": {
            const typesForComponents = parsedSelector.selectors.map(getPossibleTypes);
 
            if (typesForComponents.every(typesForComponent => typesForComponent)) {
                return lodash.union.apply(null, typesForComponents);
            }
            return null;
        }
 
        case "compound": {
            const typesForComponents = parsedSelector.selectors.map(getPossibleTypes).filter(typesForComponent => typesForComponent);
 
            // If all of the components could match any type, then the compound could also match any type.
            if (!typesForComponents.length) {
                return null;
            }
 
            /*
             * If at least one of the components could only match a particular type, the compound could only match
             * the intersection of those types.
             */
            return lodash.intersection.apply(null, typesForComponents);
        }
 
        case "child":
        case "descendant":
        case "sibling":
        case "adjacent":
            return getPossibleTypes(parsedSelector.right);
 
        default:
            return null;
 
    }
}
 
/**
 * Counts the number of class, pseudo-class, and attribute queries in this selector
 * @param {Object} parsedSelector An object (from esquery) describing the selector's matching behavior
 * @returns {number} The number of class, pseudo-class, and attribute queries in this selector
 */
function countClassAttributes(parsedSelector) {
    switch (parsedSelector.type) {
        case "child":
        case "descendant":
        case "sibling":
        case "adjacent":
            return countClassAttributes(parsedSelector.left) + countClassAttributes(parsedSelector.right);
 
        case "compound":
        case "not":
        case "matches":
            return parsedSelector.selectors.reduce((sum, childSelector) => sum + countClassAttributes(childSelector), 0);
 
        case "attribute":
        case "field":
        case "nth-child":
        case "nth-last-child":
            return 1;
 
        default:
            return 0;
    }
}
 
/**
 * Counts the number of identifier queries in this selector
 * @param {Object} parsedSelector An object (from esquery) describing the selector's matching behavior
 * @returns {number} The number of identifier queries
 */
function countIdentifiers(parsedSelector) {
    switch (parsedSelector.type) {
        case "child":
        case "descendant":
        case "sibling":
        case "adjacent":
            return countIdentifiers(parsedSelector.left) + countIdentifiers(parsedSelector.right);
 
        case "compound":
        case "not":
        case "matches":
            return parsedSelector.selectors.reduce((sum, childSelector) => sum + countIdentifiers(childSelector), 0);
 
        case "identifier":
            return 1;
 
        default:
            return 0;
    }
}
 
/**
 * Compares the specificity of two selector objects, with CSS-like rules.
 * @param {ASTSelector} selectorA An AST selector descriptor
 * @param {ASTSelector} selectorB Another AST selector descriptor
 * @returns {number}
 * a value less than 0 if selectorA is less specific than selectorB
 * a value greater than 0 if selectorA is more specific than selectorB
 * a value less than 0 if selectorA and selectorB have the same specificity, and selectorA <= selectorB alphabetically
 * a value greater than 0 if selectorA and selectorB have the same specificity, and selectorA > selectorB alphabetically
 */
function compareSpecificity(selectorA, selectorB) {
    return selectorA.attributeCount - selectorB.attributeCount ||
        selectorA.identifierCount - selectorB.identifierCount ||
        (selectorA.rawSelector <= selectorB.rawSelector ? -1 : 1);
}
 
/**
 * Parses a raw selector string, and throws a useful error if parsing fails.
 * @param {string} rawSelector A raw AST selector
 * @returns {Object} An object (from esquery) describing the matching behavior of this selector
 * @throws {Error} An error if the selector is invalid
 */
function tryParseSelector(rawSelector) {
    try {
        return esquery.parse(rawSelector.replace(/:exit$/, ""));
    } catch (err) {
        if (typeof err.offset === "number") {
            throw new Error(`Syntax error in selector "${rawSelector}" at position ${err.offset}: ${err.message}`);
        }
        throw err;
    }
}
 
/**
 * Parses a raw selector string, and returns the parsed selector along with specificity and type information.
 * @param {string} rawSelector A raw AST selector
 * @returns {ASTSelector} A selector descriptor
 */
const parseSelector = lodash.memoize(rawSelector => {
    const parsedSelector = tryParseSelector(rawSelector);
 
    return {
        rawSelector,
        isExit: rawSelector.endsWith(":exit"),
        parsedSelector,
        listenerTypes: getPossibleTypes(parsedSelector),
        attributeCount: countClassAttributes(parsedSelector),
        identifierCount: countIdentifiers(parsedSelector)
    };
});
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
/**
 * The event generator for AST nodes.
 * This implements below interface.
 *
 * ```ts
 * interface EventGenerator {
 *     emitter: EventEmitter;
 *     enterNode(node: ASTNode): void;
 *     leaveNode(node: ASTNode): void;
 * }
 * ```
 */
class NodeEventGenerator {
 
    /**
    * @param {EventEmitter} emitter - An event emitter which is the destination of events. This emitter must already
    * have registered listeners for all of the events that it needs to listen for.
    * @returns {NodeEventGenerator} new instance
    */
    constructor(emitter) {
        this.emitter = emitter;
        this.currentAncestry = [];
        this.enterSelectorsByNodeType = new Map();
        this.exitSelectorsByNodeType = new Map();
        this.anyTypeEnterSelectors = [];
        this.anyTypeExitSelectors = [];
 
        const eventNames = typeof emitter.eventNames === "function"
 
            // Use the built-in eventNames() function if available (Node 6+)
            ? emitter.eventNames()
 
            /*
             * Otherwise, use the private _events property.
             * Using a private property isn't ideal here, but this seems to
             * be the best way to get a list of event names without overriding
             * addEventListener, which would hurt performance. This property
             * is widely used and unlikely to be removed in a future version
             * (see https://github.com/nodejs/node/issues/1817). Also, future
             * node versions will have eventNames() anyway.
             */
            : Object.keys(emitter._events); // eslint-disable-line no-underscore-dangle
 
        eventNames.forEach(rawSelector => {
            const selector = parseSelector(rawSelector);
 
            if (selector.listenerTypes) {
                selector.listenerTypes.forEach(nodeType => {
                    const typeMap = selector.isExit ? this.exitSelectorsByNodeType : this.enterSelectorsByNodeType;
 
                    if (!typeMap.has(nodeType)) {
                        typeMap.set(nodeType, []);
                    }
                    typeMap.get(nodeType).push(selector);
                });
            } else {
                (selector.isExit ? this.anyTypeExitSelectors : this.anyTypeEnterSelectors).push(selector);
            }
        });
 
        this.anyTypeEnterSelectors.sort(compareSpecificity);
        this.anyTypeExitSelectors.sort(compareSpecificity);
        this.enterSelectorsByNodeType.forEach(selectorList => selectorList.sort(compareSpecificity));
        this.exitSelectorsByNodeType.forEach(selectorList => selectorList.sort(compareSpecificity));
    }
 
    /**
     * Checks a selector against a node, and emits it if it matches
     * @param {ASTNode} node The node to check
     * @param {ASTSelector} selector An AST selector descriptor
     * @returns {void}
     */
    applySelector(node, selector) {
        if (esquery.matches(node, selector.parsedSelector, this.currentAncestry)) {
            this.emitter.emit(selector.rawSelector, node);
        }
    }
 
    /**
     * Applies all appropriate selectors to a node, in specificity order
     * @param {ASTNode} node The node to check
     * @param {boolean} isExit `false` if the node is currently being entered, `true` if it's currently being exited
     * @returns {void}
     */
    applySelectors(node, isExit) {
        const selectorsByNodeType = (isExit ? this.exitSelectorsByNodeType : this.enterSelectorsByNodeType).get(node.type) || [];
        const anyTypeSelectors = isExit ? this.anyTypeExitSelectors : this.anyTypeEnterSelectors;
 
        /*
         * selectorsByNodeType and anyTypeSelectors were already sorted by specificity in the constructor.
         * Iterate through each of them, applying selectors in the right order.
         */
        let selectorsByTypeIndex = 0;
        let anyTypeSelectorsIndex = 0;
 
        while (selectorsByTypeIndex < selectorsByNodeType.length || anyTypeSelectorsIndex < anyTypeSelectors.length) {
            if (
                selectorsByTypeIndex >= selectorsByNodeType.length ||
                anyTypeSelectorsIndex < anyTypeSelectors.length &&
                compareSpecificity(anyTypeSelectors[anyTypeSelectorsIndex], selectorsByNodeType[selectorsByTypeIndex]) < 0
            ) {
                this.applySelector(node, anyTypeSelectors[anyTypeSelectorsIndex++]);
            } else {
                this.applySelector(node, selectorsByNodeType[selectorsByTypeIndex++]);
            }
        }
    }
 
    /**
     * Emits an event of entering AST node.
     * @param {ASTNode} node - A node which was entered.
     * @returns {void}
     */
    enterNode(node) {
        if (node.parent) {
            this.currentAncestry.unshift(node.parent);
        }
        this.applySelectors(node, false);
    }
 
    /**
     * Emits an event of leaving AST node.
     * @param {ASTNode} node - A node which was left.
     * @returns {void}
     */
    leaveNode(node) {
        this.applySelectors(node, true);
        this.currentAncestry.shift();
    }
}
 
module.exports = NodeEventGenerator;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/path-util.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/path-util.js

Statements: 25% (4 / 16)      Branches: 0% (0 / 6)      Functions: 0% (0 / 2)      Lines: 25% (4 / 16)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76                    1                       1                                                     1                                         1          
/**
 * @fileoverview Common helpers for operations on filenames and paths
 * @author Ian VanSchooten
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const path = require("path");
 
//------------------------------------------------------------------------------
// Private
//------------------------------------------------------------------------------
 
/**
 * Replace Windows with posix style paths
 *
 * @param {string} filepath   Path to convert
 * @returns {string}          Converted filepath
 */
function convertPathToPosix(filepath) {
    const normalizedFilepath = path.normalize(filepath);
    const posixFilepath = normalizedFilepath.replace(/\\/g, "/");
 
    return posixFilepath;
}
 
/**
 * Converts an absolute filepath to a relative path from a given base path
 *
 * For example, if the filepath is `/my/awesome/project/foo.bar`,
 * and the base directory is `/my/awesome/project/`,
 * then this function should return `foo.bar`.
 *
 * path.relative() does something similar, but it requires a baseDir (`from` argument).
 * This function makes it optional and just removes a leading slash if the baseDir is not given.
 *
 * It does not take into account symlinks (for now).
 *
 * @param {string} filepath  Path to convert to relative path.  If already relative,
 *                           it will be assumed to be relative to process.cwd(),
 *                           converted to absolute, and then processed.
 * @param {string} [baseDir] Absolute base directory to resolve the filepath from.
 *                           If not provided, all this function will do is remove
 *                           a leading slash.
 * @returns {string} Relative filepath
 */
function getRelativePath(filepath, baseDir) {
    let relativePath;
 
    if (!path.isAbsolute(filepath)) {
        filepath = path.resolve(filepath);
    }
    if (baseDir) {
        if (!path.isAbsolute(baseDir)) {
            throw new Error("baseDir should be an absolute path");
        }
        relativePath = path.relative(baseDir, filepath);
    } else {
        relativePath = filepath.replace(/^\//, "");
    }
    return relativePath;
}
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
module.exports = {
    convertPathToPosix,
    getRelativePath
};
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/rule-fixer.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/rule-fixer.js

Statements: 25% (3 / 12)      Branches: 100% (0 / 0)      Functions: 0% (0 / 9)      Lines: 25% (3 / 12)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142                                              1                             1                                                                                                                                                                                                         1    
/**
 * @fileoverview An object that creates fix commands for rules.
 * @author Nicholas C. Zakas
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
// none!
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
/**
 * Creates a fix command that inserts text at the specified index in the source text.
 * @param {int} index The 0-based index at which to insert the new text.
 * @param {string} text The text to insert.
 * @returns {Object} The fix command.
 * @private
 */
function insertTextAt(index, text) {
    return {
        range: [index, index],
        text
    };
}
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
/**
 * Creates code fixing commands for rules.
 */
 
const ruleFixer = Object.freeze({
 
    /**
     * Creates a fix command that inserts text after the given node or token.
     * The fix is not applied until applyFixes() is called.
     * @param {ASTNode|Token} nodeOrToken The node or token to insert after.
     * @param {string} text The text to insert.
     * @returns {Object} The fix command.
     */
    insertTextAfter(nodeOrToken, text) {
        return this.insertTextAfterRange(nodeOrToken.range, text);
    },
 
    /**
     * Creates a fix command that inserts text after the specified range in the source text.
     * The fix is not applied until applyFixes() is called.
     * @param {int[]} range The range to replace, first item is start of range, second
     *      is end of range.
     * @param {string} text The text to insert.
     * @returns {Object} The fix command.
     */
    insertTextAfterRange(range, text) {
        return insertTextAt(range[1], text);
    },
 
    /**
     * Creates a fix command that inserts text before the given node or token.
     * The fix is not applied until applyFixes() is called.
     * @param {ASTNode|Token} nodeOrToken The node or token to insert before.
     * @param {string} text The text to insert.
     * @returns {Object} The fix command.
     */
    insertTextBefore(nodeOrToken, text) {
        return this.insertTextBeforeRange(nodeOrToken.range, text);
    },
 
    /**
     * Creates a fix command that inserts text before the specified range in the source text.
     * The fix is not applied until applyFixes() is called.
     * @param {int[]} range The range to replace, first item is start of range, second
     *      is end of range.
     * @param {string} text The text to insert.
     * @returns {Object} The fix command.
     */
    insertTextBeforeRange(range, text) {
        return insertTextAt(range[0], text);
    },
 
    /**
     * Creates a fix command that replaces text at the node or token.
     * The fix is not applied until applyFixes() is called.
     * @param {ASTNode|Token} nodeOrToken The node or token to remove.
     * @param {string} text The text to insert.
     * @returns {Object} The fix command.
     */
    replaceText(nodeOrToken, text) {
        return this.replaceTextRange(nodeOrToken.range, text);
    },
 
    /**
     * Creates a fix command that replaces text at the specified range in the source text.
     * The fix is not applied until applyFixes() is called.
     * @param {int[]} range The range to replace, first item is start of range, second
     *      is end of range.
     * @param {string} text The text to insert.
     * @returns {Object} The fix command.
     */
    replaceTextRange(range, text) {
        return {
            range,
            text
        };
    },
 
    /**
     * Creates a fix command that removes the node or token from the source.
     * The fix is not applied until applyFixes() is called.
     * @param {ASTNode|Token} nodeOrToken The node or token to remove.
     * @returns {Object} The fix command.
     */
    remove(nodeOrToken) {
        return this.removeRange(nodeOrToken.range);
    },
 
    /**
     * Creates a fix command that removes the specified range of text from the source.
     * The fix is not applied until applyFixes() is called.
     * @param {int[]} range The range to remove, first item is start of range, second
     *      is end of range.
     * @returns {Object} The fix command.
     */
    removeRange(range) {
        return {
            range,
            text: ""
        };
    }
 
});
 
 
module.exports = ruleFixer;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/source-code-fixer.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/source-code-fixer.js

Statements: 18.42% (7 / 38)      Branches: 0% (0 / 22)      Functions: 0% (0 / 4)      Lines: 18.42% (7 / 38)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133                    1           1                 1                     1                       1                     1                                                                                                                                             1    
/**
 * @fileoverview An object that caches and applies source code fixes.
 * @author Nicholas C. Zakas
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const debug = require("debug")("eslint:text-fixer");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const BOM = "\uFEFF";
 
/**
 * Compares items in a messages array by range.
 * @param {Message} a The first message.
 * @param {Message} b The second message.
 * @returns {int} -1 if a comes before b, 1 if a comes after b, 0 if equal.
 * @private
 */
function compareMessagesByFixRange(a, b) {
    return a.fix.range[0] - b.fix.range[0] || a.fix.range[1] - b.fix.range[1];
}
 
/**
 * Compares items in a messages array by line and column.
 * @param {Message} a The first message.
 * @param {Message} b The second message.
 * @returns {int} -1 if a comes before b, 1 if a comes after b, 0 if equal.
 * @private
 */
function compareMessagesByLocation(a, b) {
    return a.line - b.line || a.column - b.column;
}
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
/**
 * Utility for apply fixes to source code.
 * @constructor
 */
function SourceCodeFixer() {
    Object.freeze(this);
}
 
/**
 * Applies the fixes specified by the messages to the given text. Tries to be
 * smart about the fixes and won't apply fixes over the same area in the text.
 * @param {SourceCode} sourceCode The source code to apply the changes to.
 * @param {Message[]} messages The array of messages reported by ESLint.
 * @returns {Object} An object containing the fixed text and any unfixed messages.
 */
SourceCodeFixer.applyFixes = function(sourceCode, messages) {
 
    debug("Applying fixes");
 
    if (!sourceCode) {
        debug("No source code to fix");
        return {
            fixed: false,
            messages,
            output: ""
        };
    }
 
    // clone the array
    const remainingMessages = [],
        fixes = [],
        bom = (sourceCode.hasBOM ? BOM : ""),
        text = sourceCode.text;
    let lastPos = Number.NEGATIVE_INFINITY,
        output = bom;
 
    messages.forEach(problem => {
        if (problem.hasOwnProperty("fix")) {
            fixes.push(problem);
        } else {
            remainingMessages.push(problem);
        }
    });
 
    if (fixes.length) {
        debug("Found fixes to apply");
 
        for (const problem of fixes.sort(compareMessagesByFixRange)) {
            const fix = problem.fix;
            const start = fix.range[0];
            const end = fix.range[1];
 
            // Remain it as a problem if it's overlapped or it's a negative range
            if (lastPos >= start || start > end) {
                remainingMessages.push(problem);
                continue;
            }
 
            // Remove BOM.
            if ((start < 0 && end >= 0) || (start === 0 && fix.text.startsWith(BOM))) {
                output = "";
            }
 
            // Make output to this fix.
            output += text.slice(Math.max(0, lastPos), Math.max(0, start));
            output += fix.text;
            lastPos = end;
        }
        output += text.slice(Math.max(0, lastPos));
 
        return {
            fixed: true,
            messages: remainingMessages.sort(compareMessagesByLocation),
            output
        };
    }
 
    debug("No fixes to apply");
    return {
        fixed: false,
        messages,
        output: bom + text
    };
 
};
 
module.exports = SourceCodeFixer;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/source-code.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/source-code.js

Statements: 8.33% (9 / 108)      Branches: 0% (0 / 99)      Functions: 0% (0 / 17)      Lines: 8.33% (9 / 108)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418                    1                               1                                                   1                                               1                     1                                                     1                                                                                                                                       1       1                                                                                                                                                                                                                                                                                                                                                                                                                                                                         1    
/**
 * @fileoverview Abstraction of JavaScript source code.
 * @author Nicholas C. Zakas
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const TokenStore = require("../token-store"),
    Traverser = require("./traverser"),
    astUtils = require("../ast-utils"),
    lodash = require("lodash");
 
//------------------------------------------------------------------------------
// Private
//------------------------------------------------------------------------------
 
/**
 * Validates that the given AST has the required information.
 * @param {ASTNode} ast The Program node of the AST to check.
 * @throws {Error} If the AST doesn't contain the correct information.
 * @returns {void}
 * @private
 */
function validate(ast) {
 
    if (!ast.tokens) {
        throw new Error("AST is missing the tokens array.");
    }
 
    if (!ast.comments) {
        throw new Error("AST is missing the comments array.");
    }
 
    if (!ast.loc) {
        throw new Error("AST is missing location information.");
    }
 
    if (!ast.range) {
        throw new Error("AST is missing range information");
    }
}
 
/**
 * Finds a JSDoc comment node in an array of comment nodes.
 * @param {ASTNode[]} comments The array of comment nodes to search.
 * @param {int} line Line number to look around
 * @returns {ASTNode} The node if found, null if not.
 * @private
 */
function findJSDocComment(comments, line) {
 
    if (comments) {
        for (let i = comments.length - 1; i >= 0; i--) {
            if (comments[i].type === "Block" && comments[i].value.charAt(0) === "*") {
 
                if (line - comments[i].loc.end.line <= 1) {
                    return comments[i];
                }
                break;
 
            }
        }
    }
 
    return null;
}
 
/**
 * Check to see if its a ES6 export declaration
 * @param {ASTNode} astNode - any node
 * @returns {boolean} whether the given node represents a export declaration
 * @private
 */
function looksLikeExport(astNode) {
    return astNode.type === "ExportDefaultDeclaration" || astNode.type === "ExportNamedDeclaration" ||
        astNode.type === "ExportAllDeclaration" || astNode.type === "ExportSpecifier";
}
 
/**
 * Merges two sorted lists into a larger sorted list in O(n) time
 * @param {Token[]} tokens The list of tokens
 * @param {Token[]} comments The list of comments
 * @returns {Token[]} A sorted list of tokens and comments
 */
function sortedMerge(tokens, comments) {
    const result = [];
    let tokenIndex = 0;
    let commentIndex = 0;
 
    while (tokenIndex < tokens.length || commentIndex < comments.length) {
        if (commentIndex >= comments.length || tokenIndex < tokens.length && tokens[tokenIndex].range[0] < comments[commentIndex].range[0]) {
            result.push(tokens[tokenIndex++]);
        } else {
            result.push(comments[commentIndex++]);
        }
    }
 
    return result;
}
 
 
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
 
/**
 * Represents parsed source code.
 * @param {string} text - The source code text.
 * @param {ASTNode} ast - The Program node of the AST representing the code. This AST should be created from the text that BOM was stripped.
 * @constructor
 */
function SourceCode(text, ast) {
    validate(ast);
 
    /**
     * The flag to indicate that the source code has Unicode BOM.
     * @type boolean
     */
    this.hasBOM = (text.charCodeAt(0) === 0xFEFF);
 
    /**
     * The original text source code.
     * BOM was stripped from this text.
     * @type string
     */
    this.text = (this.hasBOM ? text.slice(1) : text);
 
    /**
     * The parsed AST for the source code.
     * @type ASTNode
     */
    this.ast = ast;
 
    /**
     * The source code split into lines according to ECMA-262 specification.
     * This is done to avoid each rule needing to do so separately.
     * @type string[]
     */
    this.lines = [];
    this.lineStartIndices = [0];
 
    const lineEndingPattern = astUtils.createGlobalLinebreakMatcher();
    let match;
 
    /*
     * Previously, this was implemented using a regex that
     * matched a sequence of non-linebreak characters followed by a
     * linebreak, then adding the lengths of the matches. However,
     * this caused a catastrophic backtracking issue when the end
     * of a file contained a large number of non-newline characters.
     * To avoid this, the current implementation just matches newlines
     * and uses match.index to get the correct line start indices.
     */
    while ((match = lineEndingPattern.exec(this.text))) {
        this.lines.push(this.text.slice(this.lineStartIndices[this.lineStartIndices.length - 1], match.index));
        this.lineStartIndices.push(match.index + match[0].length);
    }
    this.lines.push(this.text.slice(this.lineStartIndices[this.lineStartIndices.length - 1]));
 
    this.tokensAndComments = sortedMerge(ast.tokens, ast.comments);
 
    // create token store methods
    const tokenStore = new TokenStore(ast.tokens, ast.comments);
 
    for (const methodName of TokenStore.PUBLIC_METHODS) {
        this[methodName] = tokenStore[methodName].bind(tokenStore);
    }
 
    // don't allow modification of this object
    Object.freeze(this);
    Object.freeze(this.lines);
}
 
/**
 * Split the source code into multiple lines based on the line delimiters
 * @param {string} text Source code as a string
 * @returns {string[]} Array of source code lines
 * @public
 */
SourceCode.splitLines = function(text) {
    return text.split(astUtils.createGlobalLinebreakMatcher());
};
 
SourceCode.prototype = {
    constructor: SourceCode,
 
    /**
     * Gets the source code for the given node.
     * @param {ASTNode=} node The AST node to get the text for.
     * @param {int=} beforeCount The number of characters before the node to retrieve.
     * @param {int=} afterCount The number of characters after the node to retrieve.
     * @returns {string} The text representing the AST node.
     */
    getText(node, beforeCount, afterCount) {
        if (node) {
            return this.text.slice(Math.max(node.range[0] - (beforeCount || 0), 0),
                node.range[1] + (afterCount || 0));
        }
        return this.text;
 
 
    },
 
    /**
     * Gets the entire source text split into an array of lines.
     * @returns {Array} The source text as an array of lines.
     */
    getLines() {
        return this.lines;
    },
 
    /**
     * Retrieves an array containing all comments in the source code.
     * @returns {ASTNode[]} An array of comment nodes.
     */
    getAllComments() {
        return this.ast.comments;
    },
 
    /**
     * Gets all comments for the given node.
     * @param {ASTNode} node The AST node to get the comments for.
     * @returns {Object} The list of comments indexed by their position.
     * @public
     */
    getComments(node) {
 
        let leadingComments = node.leadingComments || [];
        const trailingComments = node.trailingComments || [];
 
        /*
         * espree adds a "comments" array on Program nodes rather than
         * leadingComments/trailingComments. Comments are only left in the
         * Program node comments array if there is no executable code.
         */
        if (node.type === "Program") {
            if (node.body.length === 0) {
                leadingComments = node.comments;
            }
        }
 
        return {
            leading: leadingComments,
            trailing: trailingComments
        };
    },
 
    /**
     * Retrieves the JSDoc comment for a given node.
     * @param {ASTNode} node The AST node to get the comment for.
     * @returns {ASTNode} The BlockComment node containing the JSDoc for the
     *      given node or null if not found.
     * @public
     */
    getJSDocComment(node) {
 
        let parent = node.parent;
 
        switch (node.type) {
            case "ClassDeclaration":
            case "FunctionDeclaration":
                if (looksLikeExport(parent)) {
                    return findJSDocComment(parent.leadingComments, parent.loc.start.line);
                }
                return findJSDocComment(node.leadingComments, node.loc.start.line);
 
            case "ClassExpression":
                return findJSDocComment(parent.parent.leadingComments, parent.parent.loc.start.line);
 
            case "ArrowFunctionExpression":
            case "FunctionExpression":
 
                if (parent.type !== "CallExpression" && parent.type !== "NewExpression") {
                    while (parent && !parent.leadingComments && !/Function/.test(parent.type) && parent.type !== "MethodDefinition" && parent.type !== "Property") {
                        parent = parent.parent;
                    }
 
                    return parent && (parent.type !== "FunctionDeclaration") ? findJSDocComment(parent.leadingComments, parent.loc.start.line) : null;
                } else if (node.leadingComments) {
                    return findJSDocComment(node.leadingComments, node.loc.start.line);
                }
 
            // falls through
 
            default:
                return null;
        }
    },
 
    /**
     * Gets the deepest node containing a range index.
     * @param {int} index Range index of the desired node.
     * @returns {ASTNode} The node if found or null if not found.
     */
    getNodeByRangeIndex(index) {
        let result = null,
            resultParent = null;
        const traverser = new Traverser();
 
        traverser.traverse(this.ast, {
            enter(node, parent) {
                if (node.range[0] <= index && index < node.range[1]) {
                    result = node;
                    resultParent = parent;
                } else {
                    this.skip();
                }
            },
            leave(node) {
                if (node === result) {
                    this.break();
                }
            }
        });
 
        return result ? Object.assign({ parent: resultParent }, result) : null;
    },
 
    /**
     * Determines if two tokens have at least one whitespace character
     * between them. This completely disregards comments in making the
     * determination, so comments count as zero-length substrings.
     * @param {Token} first The token to check after.
     * @param {Token} second The token to check before.
     * @returns {boolean} True if there is only space between tokens, false
     *  if there is anything other than whitespace between tokens.
     */
    isSpaceBetweenTokens(first, second) {
        const text = this.text.slice(first.range[1], second.range[0]);
 
        return /\s/.test(text.replace(/\/\*.*?\*\//g, ""));
    },
 
    /**
    * Converts a source text index into a (line, column) pair.
    * @param {number} index The index of a character in a file
    * @returns {Object} A {line, column} location object with a 0-indexed column
    */
    getLocFromIndex(index) {
        if (typeof index !== "number") {
            throw new TypeError("Expected `index` to be a number.");
        }
 
        if (index < 0 || index > this.text.length) {
            throw new RangeError(`Index out of range (requested index ${index}, but source text has length ${this.text.length}).`);
        }
 
        /*
         * For an argument of this.text.length, return the location one "spot" past the last character
         * of the file. If the last character is a linebreak, the location will be column 0 of the next
         * line; otherwise, the location will be in the next column on the same line.
         *
         * See getIndexFromLoc for the motivation for this special case.
         */
        if (index === this.text.length) {
            return { line: this.lines.length, column: this.lines[this.lines.length - 1].length };
        }
 
        /*
         * To figure out which line rangeIndex is on, determine the last index at which rangeIndex could
         * be inserted into lineIndices to keep the list sorted.
         */
        const lineNumber = lodash.sortedLastIndex(this.lineStartIndices, index);
 
        return { line: lineNumber, column: index - this.lineStartIndices[lineNumber - 1] };
 
    },
 
    /**
    * Converts a (line, column) pair into a range index.
    * @param {Object} loc A line/column location
    * @param {number} loc.line The line number of the location (1-indexed)
    * @param {number} loc.column The column number of the location (0-indexed)
    * @returns {number} The range index of the location in the file.
    */
    getIndexFromLoc(loc) {
        if (typeof loc !== "object" || typeof loc.line !== "number" || typeof loc.column !== "number") {
            throw new TypeError("Expected `loc` to be an object with numeric `line` and `column` properties.");
        }
 
        if (loc.line <= 0) {
            throw new RangeError(`Line number out of range (line ${loc.line} requested). Line numbers should be 1-based.`);
        }
 
        if (loc.line > this.lineStartIndices.length) {
            throw new RangeError(`Line number out of range (line ${loc.line} requested, but only ${this.lineStartIndices.length} lines present).`);
        }
 
        const lineStartIndex = this.lineStartIndices[loc.line - 1];
        const lineEndIndex = loc.line === this.lineStartIndices.length ? this.text.length : this.lineStartIndices[loc.line];
        const positionIndex = lineStartIndex + loc.column;
 
        /*
         * By design, getIndexFromLoc({ line: lineNum, column: 0 }) should return the start index of
         * the given line, provided that the line number is valid element of this.lines. Since the
         * last element of this.lines is an empty string for files with trailing newlines, add a
         * special case where getting the index for the first location after the end of the file
         * will return the length of the file, rather than throwing an error. This allows rules to
         * use getIndexFromLoc consistently without worrying about edge cases at the end of a file.
         */
        if (
            loc.line === this.lineStartIndices.length && positionIndex > lineEndIndex ||
            loc.line < this.lineStartIndices.length && positionIndex >= lineEndIndex
        ) {
            throw new RangeError(`Column number out of range (column ${loc.column} requested, but the length of line ${loc.line} is ${lineEndIndex - lineStartIndex}).`);
        }
 
        return positionIndex;
    }
};
 
 
module.exports = SourceCode;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/traverser.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/traverser.js

Statements: 42.86% (3 / 7)      Branches: 100% (0 / 0)      Functions: 0% (0 / 2)      Lines: 50% (3 / 6)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47                    1           1                                                       1    
/**
 * @fileoverview Wrapper around estraverse
 * @author Nicholas C. Zakas
 */
"use strict";
 
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
 
const estraverse = require("estraverse");
 
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
 
const KEY_BLACKLIST = new Set([
    "parent",
    "leadingComments",
    "trailingComments"
]);
 
/**
 * Wrapper around an estraverse controller that ensures the correct keys
 * are visited.
 * @constructor
 */
class Traverser extends estraverse.Controller {
    traverse(node, visitor) {
        visitor.fallback = Traverser.getKeys;
        return super.traverse(node, visitor);
    }
 
    /**
     * Calculates the keys to use for traversal.
     * @param {ASTNode} node The node to read keys from.
     * @returns {string[]} An array of keys to visit on the node.
     * @private
     */
    static getKeys(node) {
        return Object.keys(node).filter(key => !KEY_BLACKLIST.has(key));
    }
}
 
module.exports = Traverser;
 
 
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/patterns/

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/patterns/

Statements: 100% (1 / 1)      Branches: 100% (0 / 0)      Functions: 100% (0 / 0)      Lines: 100% (1 / 1)      Ignored: none     

All files » node-npmtest-eslint/node_modules/eslint/lib/util/patterns/
File Statements Branches Functions Lines
letters.js 100% (1 / 1) 100% (0 / 0) 100% (0 / 0) 100% (1 / 1)
Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/patterns/letters.js

npmtest-eslint (v0.0.3)

Code coverage report for node-npmtest-eslint/node_modules/eslint/lib/util/patterns/letters.js

Statements: 100% (1 / 1)      Branches: 100% (0 / 0)      Functions: 100% (0 / 0)      Lines: 100% (1 / 1)      Ignored: none     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39                                                                      1      
/**
 * @fileoverview Pattern for detecting any letter (even letters outside of ASCII).
 * NOTE: This file was generated using this script in JSCS based on the Unicode 7.0.0 standard: https://github.com/jscs-dev/node-jscs/blob/f5ed14427deb7e7aac84f3056a5aab2d9f3e563e/publish/helpers/generate-patterns.js
 * Do not edit this file by hand-- please use https://github.com/mathiasbynens/regenerate to regenerate the regular expression exported from this file.
 * @author Kevin Partington
 * @license MIT License (from JSCS). See below.
 */
 
/*
 * The MIT License (MIT)
 *
 * Copyright 2013-2016 Dulin Marat and other contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
"use strict";
 
module.exports = /[A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B2\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF40\uDF42-\uDF49\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF]|\uD801[\uDC00-\uDC9D\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDE00-\uDE11\uDE13-\uDE2B\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF5D-\uDF61]|\uD805[\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDE00-\uDE2F\uDE44\uDE80-\uDEAA]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF98]|[\uD80C\uD840-\uD868\uD86A-\uD86C][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D]|\uD87E[\uDC00-\uDE1D]/;